2012-03-28 2 views
2

У меня есть просмотр редактора объектов, который отображает простые данные, а также интерпретацию значения, которое шаблонизируется с использованием TemplateSelector. Если исходное значение обновляется, значит, и интерпретируемое значение, и наоборот. В простой DataTemplate он работает хорошо, но у меня есть более сложный сценарий, где значение (ushort) представляет растровое изображение (поле флагов). Для этого я использую ItemControl с ItemTemplate. Это работает нормально в направлении value-> flags, но не при нажатии флажков. Я в MVVM мире, так что не хотят быть реакцией на события в xaml.cs файлов ...Двусторонняя привязка данных в DataTemplate через TemplateSelector

The View Ресурсы из:

<DataTemplate x:Key="StandardTemplate"> 
     <StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> 
      <TextBox Margin="0" VerticalAlignment="Top" Width="50" Text="{Binding Formatted,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" /> 
     </StackPanel> 
    </DataTemplate> 

    <DataTemplate x:Key="BitmapTemplate" > 
     <ItemsControl ItemsSource="{Binding Flags,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" > 
      <ItemsControl.ItemsPanel> 
       <ItemsPanelTemplate> 
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" /> 
       </ItemsPanelTemplate> 
      </ItemsControl.ItemsPanel> 

      <ItemsControl.ItemTemplate> 
       <DataTemplate> 
        <StackPanel HorizontalAlignment="Center" Width="20"> 
         <TextBlock Text="{Binding BitPosition,Converter={StaticResource intConverter},ConverterParameter=1}" HorizontalAlignment="Center" /> 
         <CheckBox HorizontalAlignment="Center" HorizontalContentAlignment="Center" IsChecked="{Binding IsBitSet,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" /> 
        </StackPanel> 
       </DataTemplate> 
      </ItemsControl.ItemTemplate> 

     </ItemsControl> 
    </DataTemplate> 


    <selectors:EditTemplateSelector x:Key="EditSelector" BitmapTemplate="{StaticResource BitmapTemplate}" StandardTemplate="{StaticResource StandardTemplate}" /> 

Он получает на взгляд:

<ContentPresenter Content="{Binding Register}" Grid.Row="2" Grid.ColumnSpan="2" Margin="10" ContentTemplateSelector="{StaticResource EditSelector}" /> 

Мои Растровые и BitmapBit классы:

public class BitmapBit : ObservableObject 
{ 
    ushort _bitPosition = 0; 
    bool _isSet = false; 

    public BitmapBit(ushort bitPos, bool isSet) 
    { 
     _bitPosition = bitPos; 
     _isSet = isSet; 
    } 

    public ushort BitPosition 
    { 
     get { return _bitPosition; } 
     set 
     { 
      if (_bitPosition == value) 
       return; 

      _bitPosition = value; 
      RaisePropertyChanged("BitPosition"); 
     } 
    } 

    public bool IsBitSet 
    { 
     get { return _isSet; } 
     set 
     { 
      if (_isSet == value) 
       return; 

      _isSet = value; 
      RaisePropertyChanged("IsBitSet"); 
     } 
    } 
} 

/// <summary> 
/// A collection of BitmapBits 
/// </summary> 
public class Bitmap : ObservableCollection<BitmapBit> 
{ 
    const ushort NUMBER_OF_BITS = sizeof(ushort) * 8; // 8 BITS_IN_A_BYTE 

    protected Bitmap(ushort value) : base() 
    { 
     for (ushort i = 0; i < NUMBER_OF_BITS; ++i) 
      Insert(0, new BitmapBit(bitPos: i, isSet: (value & (1 << i)) != 0)); 
    } 


    public static Bitmap Create(ushort value) 
    { 
     return new Bitmap(value); 
    } 

    public static ushort Parse(Bitmap bits) 
    { 
     ushort generated = 0; 
     foreach (BitmapBit bit in bits) 
      generated += (ushort)(bit.IsBitSet ? 2^bit.BitPosition : 0); 
     return generated; 
    } 
} 

IsBitSet сеттер называется, но я думаю, что проблема в том, что Bitma p не участвует в уведомлении о том, что бит изменился - так что установщик Flags никогда не вызван. Как обновить/уведомить свойство Flags при изменении члена ObservableCollection?

ответ

1

Это связано с тем, что ваши флажки обновляют объекты BitmapBit, которые были созданы вашим конвертером. Они ничего не знают о самом конвертере, который был вызван отдельно вашим ItemsControl.

Если вы хотите, чтобы оригинальное ухорт обновлялось, вы действительно хотите разоблачить коллекцию BitmapBit непосредственно из ViewModel, а не через конвертер. Таким образом, вы можете обновить ссылку на VM в объекте BitmapBit и обновить ushort в сетевом устройстве BitmapBit.

EDIT: Ваш отредактирован, но проблема по-прежнему в значительной степени связана с тем, что я получаю. BitmapBits не знают базового Bitmap, поэтому не обновляйте его.

Вы не показываете, как определяется ваш Flags, поэтому я не могу показать вам, как его обновлять, но в основном все, что вам нужно сделать, это следить за изменениями на каждом BitmapBit, как и в случае с View, подписавшись на PropertyChanged :

protected Bitmap(ushort value) : base() 
{ 
    for (ushort i = 0; i < NUMBER_OF_BITS; ++i) 
    { 
     var bit = new BitmapBit(bitPos: i, isSet: (value & (1 << i)) != 0); 
     bit.PropertyChanged += (s, e) => UpdateFlags(); 
     Insert(0, bit); 
    } 
} 
+0

А я вижу, что вы получаете, а мое редактирование отражает удаление конвертера - что, как вы правильно указываете, добавляет слой замешательства. Думаю, основная проблема теперь яснее, но у меня все еще нет решения! – AndyC

+0

Редактировал мой ответ – GazTheDestroyer

+0

Lightbulb moment! Это недостающее звено; Конструкция битмапа теперь принимает объект, который генерирует растровое изображение, поэтому флаги могут обновляться при изменении бит. Спасибо, что провел меня! – AndyC