子ViewModel属性的PropertyChanged值为null



我有一个ObservableCollection的ViewModels在我的主ViewModel。绑定似乎工作得很好,因为我可以切换视图。然而,在ObservableCollection的元素中引发ViewModelBase OnPropertyChanged方法(该方法适用于其他东西)会导致ViewModelBase中的PropertyChanged值为空。

下面是我的主要代码片段:

在我的主ViewModel构造函数:

    public EditorViewModel()
    {
        base.DisplayName = Strings.EditorName;
        _availableEditors = new ObservableCollection<ViewModelBase>();
        AvailableEditors.Add(new GBARomViewModel(646, 384));
        AvailableEditors.Add(new MonsterViewModel(800, 500));
        CurrentEditor = _availableEditors[0];
    }

在GBA ROM加载时,ViewModel和Model属性被更新:

    void RequestOpenRom()
    {
        OpenFileDialog dlg = new OpenFileDialog();
        dlg.DefaultExt = ".gba";
        dlg.Filter = "GBA ROM (.gba)|*.gba|All files (*.*)|*.*";
        dlg.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
        Nullable<bool> result = dlg.ShowDialog();
        if (result == true)
        {
            if(CurrentEditor is GBARomViewModel)
            {
                (CurrentEditor as GBARomViewModel).ReadRom(dlg.FileName);
            }               
        }
    }

在我的主视图: TabControl的变化(有视图切换和视图状态保存)。

    <controls:TabControlEx ItemsSource="{Binding AvailableEditors}"
        SelectedItem="{Binding CurrentEditor}"
        Style="{StaticResource BlankTabControlTemplate}"
        MinWidth="{Binding CurrentEditorWidth}"
        MinHeight="{Binding CurrentEditorHeight}"
        MaxWidth="{Binding CurrentEditorWidth}"
        MaxHeight="{Binding CurrentEditorHeight}"
        Width="{Binding CurrentEditorWidth}"
        Height="{Binding CurrentEditorHeight}"
        HorizontalAlignment="Left"
        VerticalAlignment="Top">
        <controls:TabControlEx.Resources>
            <DataTemplate DataType="{x:Type vm:GBARomViewModel}">
                <vw:GBARomView />
            </DataTemplate>
            <DataTemplate DataType="{x:Type vm:MonsterViewModel}">
                <vw:MonsterView />
            </DataTemplate>
        </controls:TabControlEx.Resources>
    </controls:TabControlEx>

In GBARomViewModel(子ViewModel, AvailableEditors的元素)

    public String CRC32
    {
        get
        {
            return _rom.CRC32;
        }
        set
        {
            if (value.Equals(_rom.CRC32))
            {
                return;
            }
            _rom.CRC32 = value;
            OnPropertyChanged("CRC32");
        }
    }

子视图中的属性绑定
这是一个UserControl所以我将把它的代码也放在后面。启动时的其他属性,如LabelWidth和LabelValue。在XAML中给TextBoxValue一个默认值也可以。

    <StackPanel VerticalAlignment="Bottom" HorizontalAlignment="Left" Margin="10, 0, 0, 10" Width="300">
        <dlb:DefaultLabelBox LabelWidth="82" TextBoxWidth="100" HorizontalAlignment="Left" LabelValue="{x:Static p:Strings.RomTitle}" TextBoxValue="{Binding Title}" />
        <dlb:DefaultLabelBox LabelWidth="82" TextBoxWidth="100" HorizontalAlignment="Left" LabelValue="{x:Static p:Strings.RomGameCode}" TextBoxValue="{Binding GameCode}" />
        <dlb:DefaultLabelBox LabelWidth="82" TextBoxWidth="100" HorizontalAlignment="Left" LabelValue="{x:Static p:Strings.RomRomSize}" TextBoxValue="{Binding RomSize}"  />
        <dlb:DefaultLabelBox LabelWidth="82" TextBoxWidth="100" HorizontalAlignment="Left" LabelValue="{x:Static p:Strings.RomCRC32}" TextBoxValue="{Binding CRC32}"  />
        <dlb:DefaultLabelBox LabelWidth="82" TextBoxWidth="200" HorizontalAlignment="Left" LabelValue="{x:Static p:Strings.RomMD5Checksum}" TextBoxValue="{Binding MD5Checksum}"/>
    </StackPanel>

DefaultLabelBox.cs

<UserControl x:Name="uc">
    <StackPanel>
        <TextBlock Text="{Binding Path=LabelValue, ElementName=uc}"
           Width="{Binding Path=LabelWidth, ElementName=uc}"/>
        <Label Content="{Binding Path=TextBoxValue, Mode=OneWay, ElementName=uc}"
         Width="{Binding Path=TextBoxWidth, ElementName=uc}"/>
    </StackPanel>
</UserControl>

DefaultLabelBox.xaml.cs

    public string TextBoxValue
    {
        get {
            return (string)GetValue(TextBoxValueProperty);
        }
        set {
            SetValue(TextBoxValueProperty, value);
        }
    }
    public static readonly DependencyProperty TextBoxValueProperty =
        DependencyProperty.Register("TextBoxValue", typeof(string), typeof(DefaultLabelBox), new PropertyMetadata(default(string)));
控制模板

<Style TargetType="dlb:DefaultLabelBox">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="dlb:DefaultLabelBox">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding LabelValue, RelativeSource={RelativeSource TemplatedParent}}"
                               MinWidth="20"
                               Width="{Binding LabelWidth, RelativeSource={RelativeSource TemplatedParent}}"
                               VerticalAlignment="Center"
                               FontFamily="Mangal"
                               Height="20"
                               FontSize="13"/>
                    <Label Content="{Binding TextBoxValue, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"
                           BorderBrush="{StaticResource DefaultLabelBoxBorderBrush}"
                           BorderThickness="1"
                           Padding="1,1,1,1"
                           Background="{StaticResource DefaultLabelBoxBackgroundBrush}"
                           Foreground="{StaticResource DefaultLabelBoxForeground}"
                               MinWidth="60"
                               Height="20"
                               VerticalAlignment="Center"
                               FontFamily="Mangal"
                               Width="{Binding TextBoxWidth, RelativeSource={RelativeSource TemplatedParent}}" 
                               FontSize="13"/>
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

我尝试了一些事情,但作为MVVM的新手,我不知道我是否有一个绑定的DataContext问题。如有任何帮助,不胜感激。

Edit:我对一些代码进行了更改,以说明为我提供的工作解决方案以及添加我忘记的ControlTemplate。我不确定Mode=OneWay是否在UserControl和ControlTemplate中是强制性的,但它现在正在工作,所以我让它保持原样

为了创建一个像

这样的绑定
<dlb:DefaultLabelBox ... TextBoxValue="{Binding CRC32, Mode=TwoWay}" />

工作时,DefaultLabelBox需要从它的父控件继承它的DataContext(这是btw。这就是为什么UserControl不应该显式地设置它的DataContext的原因。

然而,UserControl的XAML中的"内部"绑定需要显式指定Source或RelativeSource或ElementName。

所以它们应该(例如)看起来像这样:

<UserControl ... x:Name="uc">
    <StackPanel>
        <TextBlock
             Text="{Binding Path=LabelValue, ElementName=uc}"
             Width="{Binding Path=LabelWidth, ElementName=uc}"/>
        <TextBox
            Text="{Binding Path=TextBoxValue, Mode=TwoWay, ElementName=uc}"
            Width="{Binding Path=TextBoxWidth, ElementName=uc}"/>
    </StackPanel>
</UserControl>

相关内容

  • 没有找到相关文章

最新更新