【问题标题】:Two-way data binding in DataTemplate via TemplateSelector通过 TemplateSelector 在 DataTemplate 中进行双向数据绑定
【发布时间】:2012-03-28 13:32:01
【问题描述】:

我有一个对象编辑器视图,它显示简单数据以及一个值的解释,它是使用 TemplateSelector 模板化的。如果原始值得到更新,解释值也会更新,反之亦然。在一个简单的 DataTemplate 中它运行良好,但我有一个更复杂的场景,其中值(一个 ushort)代表一个位图(标志字段)。为此,我将 ItemsControl 与 ItemTemplate 一起使用。这在 value->flags 方向上可以正常工作,但在单击标志时不行。我在 MVVM 世界,所以不想对 xaml.cs 文件中的事件做出反应......

视图的资源:

    <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 不涉及 Bit 已更改的通知 - 因此永远不会调用 Flags 设置器。当其 ObservableCollection 的成员发生更改时,如何更新/通知 Flags 属性?

【问题讨论】:

    标签: c# wpf xaml data-binding mvvm


    【解决方案1】:

    这是因为您的复选框正在更新由转换器创建的 BitmapBit 对象。他们对您的 ItemsControl 单独调用的转换器本身一无所知。

    如果您希望更新原始 ushort,那么您确实希望直接从您的 ViewModel 中公开 BitmapBit 集合,而不是通过转换器。这样您就可以更新在BitmapBit 对象中保留VM 引用,并在BitmapBit 设置器中更新ushort。

    编辑: 你的编辑澄清了一点,但问题仍然是我遇到的问题。 BitmapBits 不知道底层 Bitmap,所以不要更新它。

    你没有显示你的Flags 是如何定义的,所以我不能告诉你如何更新它,但基本上你需要做的就是像 View 一样观察每个 BitmapBit 上的变化,通过订阅属性更改:

    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);
         }
    } 
    

    【讨论】:

    • 啊,我明白了你的意思,我的编辑反映了转换器的删除 - 正如你正确指出的那样,这增​​加了一层混乱。我认为根本问题现在更清楚了,但我仍然没有解决方案!
    • 灯泡时刻!那是缺失的环节;位图构造现在采用生成位图的对象,因此可以在位更改时更新标志。感谢您带领我完成!
    猜你喜欢
    • 1970-01-01
    • 2020-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多