powered by simpleCommunicator - 2.0.51     © 2025 Programmizd 02
Форумы / WPF, Silverlight [игнор отключен] [закрыт для гостей] / DataTemplate и неявное преобразование
4 сообщений из 4, страница 1 из 1
DataTemplate и неявное преобразование
    #39023644
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сегодня захотел облегчить себе жизнь :) как обычно, но всё оказалось не так просто.
Все мы знаем ситуацию, когда надо создать аля CheckBoxList в котором будут перечислены какие то сущности.
Так как сама по себе сущность может не предусматривать свойства IsChecked или какой то подобной, не возможно связывать выделение во View с ViewModel, в результате мы не можем понять, выделены или нет эти объекты.
Я логично предположил, что было бы удобно создать Generic обёртку для таких ситуаций, которая бы просто добавила мне свойство IsChecked, а работать это должно точно так же как и с Nullable<T>.
В результате получился следующий класс:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
    public class CheckBoxWrapper<T> : IEquatable<CheckBoxWrapper<T>> 
    {
        public bool Equals(CheckBoxWrapper<T> other)
        {
            if (ReferenceEquals(null, other)) return false;
            if (ReferenceEquals(this, other)) return true;
            return EqualityComparer<T>.Default.Equals(_value, other._value);
        }

        public override int GetHashCode()
        {
            return EqualityComparer<T>.Default.GetHashCode(_value);
        }

        public static bool operator ==(CheckBoxWrapper<T> left, CheckBoxWrapper<T> right)
        {
            return Equals(left, right);
        }

        public static bool operator !=(CheckBoxWrapper<T> left, CheckBoxWrapper<T> right)
        {
            return !Equals(left, right);
        }

        private readonly T _value;
        private bool? _isChecked;

        public CheckBoxWrapper(T value)
        {
            _value = value;
        }

        public T Value
        {
            get { return _value; }
        }

        public bool? IsChecked
        {
            get { return _isChecked; }
            set { _isChecked = value; }
        }

        public static implicit operator T(CheckBoxWrapper<T> value)
        {
            return value.Value;
        }

        public static implicit operator CheckBoxWrapper<T>(T value)
        {
            return new CheckBoxWrapper<T>(value);
        }


        public override bool Equals(object obj)
        {
            return _value.Equals(obj);
        }

        public override string ToString()
        {
            return _value.ToString();
        }
    }


В классе 2 основных метода, на которые я возлагал свои надежды, это операторы неявного преобразования. Ведь я как наивный дурак предполагал, что DataTemplate будет преобразовывать объект в тот, который указан в свойстве DataType и всё будет прозрачно, точно так же как Nullable<T>. Но не тут то было.
Накидав пример
Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
<Window x:Class="DataTemplateImplicit.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:dataTemplateImplicit="clr-namespace:DataTemplateImplicit"
        Title="MainWindow" Height="350" Width="525"
        DataContext="{StaticResource MainModel}">
    <Window.Resources>
        <DataTemplate x:Key="ItemTemplate" 
                      DataType="{x:Type dataTemplateImplicit:Person}">
            <UniformGrid Columns="2" Background="BurlyWood" Height="32" Margin="2">
                <TextBlock Text="{Binding Name}"/>
                <TextBlock Text="{Binding Age}"/>
            </UniformGrid>
        </DataTemplate>
    </Window.Resources>
    <UniformGrid Columns="3" >
        <ItemsControl ItemsSource="{Binding Persons}" ItemTemplate="{StaticResource ItemTemplate}"/>
        <ItemsControl ItemsSource="{Binding NullablePerson}" ItemTemplate="{StaticResource ItemTemplate}"/>
        <ItemsControl ItemsSource="{Binding CheckingPerson}" ItemTemplate="{StaticResource ItemTemplate}"/>
                      
    </UniformGrid>
</Window>


Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
    public struct Person
    {
        public string Name { set; get; }
        public int Age { set; get; }
    }

    public class MainModel
    {
        public List<Person> Persons { set; get; }

        public List<Nullable<Person>> NullablePerson { set; get;}

        public List<CheckBoxWrapper<Person>> CheckingPerson { set; get; }

        public MainModel()
        {
            Persons = new List<Person>
            {
                new Person {Name = "Roman", Age = 32},
                new Person {Name = "Sofia", Age = 35},
                new Person {Name = "Olga", Age = 6},
                new Person {Name = "Sasha", Age = 14},
            };

            NullablePerson = new List<Person?>
            {
                Persons[0],
                null,
                Persons[1],
                null,
                Persons[2],
                null,
                Persons[3]
            };
            CheckingPerson = new List<CheckBoxWrapper<Person>>
            {
                Persons[0],
                Persons[1],
                Persons[2],
                Persons[3]
            };
        }
    }


я выяснил, что с Nullable всё работает, а с мои классом не работает. В чем грабли?
...
Рейтинг: 0 / 0
DataTemplate и неявное преобразование
    #39023822
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
у меня есть переменная типа Type (указывающая на типа Class1), мне нужно получить объект этого типа, из объекта другого типа (Class2) в котором определен оператор implicit для для преобразования из Class2 в Class1. Как это сделать?
...
Рейтинг: 0 / 0
DataTemplate и неявное преобразование
    #39025911
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Roman Mejtesу меня есть переменная типа Type (указывающая на типа Class1), мне нужно получить объект этого типа, из объекта другого типа (Class2) в котором определен оператор implicit для для преобразования из Class2 в Class1. Как это сделать?
Только через рефлекшен, выдергивая у Class1 public static Class1 op_Implicit(Class2), потому как компилятор при преобразованиях через operator implicit/explicit вставляет в IL-код вызовы именно этих операторов:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
namespace test
{
  class Program
  {
    static void Main(string[] args)
    {
      int n = 123;
      Test(n);
      Console.WriteLine("done");
      Console.ReadKey(true);
    }

    static void Test(Decimal d)
    {
      Console.WriteLine(d);
    }
  }
}


Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       32 (0x20)
  .maxstack  1
  .locals init ([0] int32 n)
  IL_0000:  ldc.i4.s   123
  IL_0002:  stloc.0
  IL_0003:  ldloc.0
  IL_0004:  call       valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::op_Implicit(int32)
  IL_0009:  call       void test.Program::Test(valuetype [mscorlib]System.Decimal)
  IL_000e:  ldstr      "done"
  IL_0013:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0018:  ldc.i4.1
  IL_0019:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey(bool)
  IL_001e:  pop
  IL_001f:  ret
} // end of method Program::Main


Ну, а поскольку биндинг работает через рефлекшн, но, видимо, не ориентируется на наличие операторов преобразования в типе, то и не вызывает эти операторы, а работает всё так же - просто по заданным в разметке свойствам, которых непосредственно у класса-враппера нет. Что же до Nullable<T> - это особый случай, у этого типа поддержка зашита глубоко на уровне CLR, и с ним преобразования работают. В частности, см. Рихтера по нюансы вызова GetType у Nullable<T>:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
namespace test
{
  struct Foo {}
  class Program
  {
    static void Main(string[] args)
    {
      Console.WriteLine(new Nullable<Foo>(new Foo()).GetType().FullName);
      Console.ReadKey(true);
    }
  }
}


- в консольном выводе будет test.Foo.
А по поводу "облегчить жизнь" - я бы просто прикрутил IValueConverter, конвертящий из экземпляра враппера в нужный тип. Так действительно будет проще.
...
Рейтинг: 0 / 0
DataTemplate и неявное преобразование
    #39026162
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сон Веры ПавловныRoman Mejtesу меня есть переменная типа Type (указывающая на типа Class1), мне нужно получить объект этого типа, из объекта другого типа (Class2) в котором определен оператор implicit для для преобразования из Class2 в Class1. Как это сделать?
Только через рефлекшен, выдергивая у Class1 public static Class1 op_Implicit(Class2), потому как компилятор при преобразованиях через operator implicit/explicit вставляет в IL-код вызовы именно этих операторов:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
namespace test
{
  class Program
  {
    static void Main(string[] args)
    {
      int n = 123;
      Test(n);
      Console.WriteLine("done");
      Console.ReadKey(true);
    }

    static void Test(Decimal d)
    {
      Console.WriteLine(d);
    }
  }
}


Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       32 (0x20)
  .maxstack  1
  .locals init ([0] int32 n)
  IL_0000:  ldc.i4.s   123
  IL_0002:  stloc.0
  IL_0003:  ldloc.0
  IL_0004:  call       valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::op_Implicit(int32)
  IL_0009:  call       void test.Program::Test(valuetype [mscorlib]System.Decimal)
  IL_000e:  ldstr      "done"
  IL_0013:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0018:  ldc.i4.1
  IL_0019:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey(bool)
  IL_001e:  pop
  IL_001f:  ret
} // end of method Program::Main


Ну, а поскольку биндинг работает через рефлекшн, но, видимо, не ориентируется на наличие операторов преобразования в типе, то и не вызывает эти операторы, а работает всё так же - просто по заданным в разметке свойствам, которых непосредственно у класса-враппера нет. Что же до Nullable<T> - это особый случай, у этого типа поддержка зашита глубоко на уровне CLR, и с ним преобразования работают. В частности, см. Рихтера по нюансы вызова GetType у Nullable<T>:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
namespace test
{
  struct Foo {}
  class Program
  {
    static void Main(string[] args)
    {
      Console.WriteLine(new Nullable<Foo>(new Foo()).GetType().FullName);
      Console.ReadKey(true);
    }
  }
}


- в консольном выводе будет test.Foo.
А по поводу "облегчить жизнь" - я бы просто прикрутил IValueConverter, конвертящий из экземпляра враппера в нужный тип. Так действительно будет проще.
Спасибо большое, на счет op_Implicit Уже сам проникся, но отказался от всей этой идеи, запилил просто 2 шаблона и бог с ним, жаль, конечно, по сути получается, что DataType свойство особого смысла не имеет. Как я понял из кода DataTemplate, оно используется только в задании ключа ресурса (как TargetType) и для дизайнера.
Иногда WPF раздражающе негибок, особенно касательно Internal классов, свойств и методов. Которые охота переопределить, но возможности такой нет =( надеюсь когда нибудь мы увидим изменения в этом направлении, а то WPF последнее время вообще кое как обновляется.
...
Рейтинг: 0 / 0
4 сообщений из 4, страница 1 из 1
Форумы / WPF, Silverlight [игнор отключен] [закрыт для гостей] / DataTemplate и неявное преобразование
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]