Двусторонняя привязка данных в DataTemplate через TemplateSelector - PullRequest
2 голосов
/ 28 марта 2012

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

Ресурсы 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}" />

Мои классы Bitmap и 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, но я думаю, что проблема в том, что Bitmap не участвует в уведомлении о том, что битизменилось - так что установщик флагов никогда не вызывается.Как обновить / уведомить свойство Flags при изменении члена его ObservableCollection?

1 Ответ

1 голос
/ 28 марта 2012

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

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

EDIT : Ваша редакция немного прояснила ситуацию, но проблема все еще в значительной степени заключается в том, к чему я стремился. Битовые биты не знают о базовой битовой карте, поэтому не обновляйте ее.

Вы не показываете, как определяется ваш 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);
     }
} 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...