C# 通过TemplateSelector在DataTemplate中进行双向数据绑定

C# 通过TemplateSelector在DataTemplate中进行双向数据绑定,c#,wpf,xaml,data-binding,mvvm,C#,Wpf,Xaml,Data Binding,Mvvm,我有一个对象编辑器视图,它显示简单的数据和一个值的解释,该值是使用TemplateSelector模板化的。如果原始值得到更新,则解释值也会更新,反之亦然。在一个简单的DataTemplate中,它工作得很好,但我有一个更复杂的场景,其中值(ushort)表示位图(标志字段)。为此,我将ItemsControl与ItemTemplate一起使用。这在值->标志方向上正常工作,但在单击标志时无效。我身处MVVM世界,所以不想对xaml.cs文件中的事件做出反应 视图的资源: <Dat

我有一个对象编辑器视图,它显示简单的数据和一个值的解释,该值是使用TemplateSelector模板化的。如果原始值得到更新,则解释值也会更新,反之亦然。在一个简单的DataTemplate中,它工作得很好,但我有一个更复杂的场景,其中值(ushort)表示位图(标志字段)。为此,我将ItemsControl与ItemTemplate一起使用。这在值->标志方向上正常工作,但在单击标志时无效。我身处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}" />

我的位图和位图类是:

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;
    }
}
公共类BitmapBit:ObservableObject
{
ushort _bitPosition=0;
bool_isSet=false;
公共位图位(ushort bitPos、bool isSet)
{
_比特位置=比特位置;
_isSet=isSet;
}
公共位置
{
获取{return\u bitPosition;}
设置
{
if(_bitPosition==值)
返回;
_位位置=值;
RaisePropertyChanged(“位位置”);
}
}
公共布尔IsBitSet
{
获取{return\u isSet;}
设置
{
如果(_isSet==值)
返回;
_isSet=值;
RaisePropertyChanged(“IsBitSet”);
}
}
}
/// 
///位图位的集合
/// 
公共类位图:ObservableCollection
{
常量ushort NUMBER\u OF_BITS=sizeof(ushort)*8;//字节中的8位
受保护位图(ushort值):base()
{
对于(ushort i=0;i<位的个数;++i)

插入(0,新BitmapBit)(bitPos:i,isSet:(value&(1这是因为您的复选框正在更新由转换器创建的
BitmapBit
对象。它们对由ItemsControl单独调用的转换器本身一无所知

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

编辑: 您的编辑清除了一点,但问题仍然与我所了解的差不多。BitmapBits不知道底层位图,所以不要更新它

您没有显示如何定义
标志,因此我无法显示如何更新它,但基本上您需要做的就是像视图一样,通过订阅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);
     }
} 
受保护位图(ushort值):base()
{ 
对于(ushort i=0;i<位的个数;++i)
{
var bit=新的位图位(bitPos:i,isSet:(value&(1 UpdateFlags());
插入(0,位);
}
} 

Ah我明白你的意思,我的编辑反映了转换器的删除——正如你正确指出的那样,这增加了一层混乱。我认为根本的问题现在更清楚了,但我仍然没有解决方案!Lightbull时刻!这是缺少的链接;位图构造现在使用生成位图的对象,因此旗帜可以更新时,有点变化。谢谢你引导我通过!