相关性属性更改时,StackPanel可见性未更新



我目前正在用MVVM(而不是MVVM Light)在C#/XAML中开发一个通用应用程序,但我在XAML部分遇到了问题。

当ViewModel中的依赖项属性发生更改时,我希望显示一个或另一个StackPanel。我认为代码不言自明。

<StackPanel Visibility="{Binding MyProperty, Converter={StaticResource BooleanToVisibilityConverter}}">
    <!-- Some content -->
</StackPanel>
<StackPanel Visibility="{Binding MyProperty, Converter={StaticResource InvertBooleanToVisibilityConverter}}">
    <!-- Some another content -->
</StackPanel>

这是依赖属性的定义。

public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register(
    "MyProperty",
    typeof (bool),
    typeof (MyViewModel),
    new PropertyMetadata(true));
public bool MyProperty
{
    get { return (bool) GetValue(MyPropertyProperty); }
    set { SetValue(MyPropertyProperty, value); OnPropertyChanged(); // Implemented by ReSharper }
}

我想你已经知道MyProperty是一个布尔值,我通过转换器将其转换为Visibility。因此,当MyProperty在ViewModel中发生更改时,视图不会更新。

我已经尝试使用UpdateSourceTrigger属性,但它不起作用。此外,我没有绑定错误,转换器工作正常(我在应用程序启动时只看到一个StackPanel)。

请记住,除非没有其他解决方案,否则我不想使用代码隐藏部分。

谢谢你的帮助。

我最终放弃了,使用了代码隐藏部分,现在它工作得很好。

您的<StackPanel>是某些UserControl的一部分吗?如果没有,为什么要使用DependencyProperty

您的实现也相当糟糕。

让我们假设一下,这不是自定义控制的一部分(纠正我——如果我错了,我会重写解决方案)

所以你有一个ViewModel,你想把一些Properties连接到它上。你真的不需要实现DependencyProperty来做你想做的事情,但我会通过你的方式来实现它来娱乐你。

这是一个具有1(一)属性的示例ViewModel

using Windows.UI.Xaml;
using System.ComponentModel;
// very simple view model
class MyViewModel : DependencyObject, INotifyPropertyChanged
{
    // implement INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    } 
    // register
    public static DependencyProperty FooterTitleProperty = DependencyProperty.Register("FooterTitle", typeof(string), typeof(MyViewModel),
         new PropertyMetadata(string.Empty, OnFooterTitlePropertyChanged));
    // the actual property
    public string FooterTitle
    {
        get { return (string) GetValue(FooterTitleProperty); }
        set
        {
            SetValue(FooterTitleProperty, value);
        }
    }
    // this will fire when the property gets change
    // it will call the OnPropertyChanged to notify the UI element to update its layout
    private static void OnFooterTitlePropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
    {
        MyViewModel mvm = dependencyObject as MyViewModel;
        mvm.OnPropertyChanged("FooterTitle");
    }
}

为了测试代码,我们将制作一个非常简单的XAML表单

<Grid x:Name="ContentPanel">
    <StackPanel>
        <TextBlock x:Name="tb" Text="{Binding FooterTitle}" FontSize="48"></TextBlock>
        <Button Content="Test Property" Click="Button_Click_1"></Button>
    </StackPanel>
</Grid>

当您点击按钮时,我们将更改文本框的文本

public sealed partial class MainPage : Page
{
    // create the view model
    MyViewModel vm = new MyViewModel();
    public MainPage()
    {
        this.InitializeComponent();
        this.NavigationCacheMode = NavigationCacheMode.Required;

        // set the text we initial want to display
        vm.FooterTitle = "default text";
        // set the DataContext of the textbox to the ViewModel
        tb.DataContext = vm;
    }

    // after the button is click we change the TextBox's Text
    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        // change the text
        vm.FooterTitle = "Test Property Has Changed.";
        // what happens is the Setter of the Property is called first
        // after that happens it launches the `OnFooterTitlePropertyChanged` event
        // that we hook up with the Register function.

        // `OnFooterTitlePropertyChanged` launches the INotifyPropertyChanged event
        // then finally the TextBox will updates it's layout
    }
}

在这一点上,你可以猜测你真的不需要DependencyProperty,并说为什么我不能在Setter中启动INotifyPropertyChanged?你可以,而且这可能是你更喜欢的方法。

如果所有这些都是UserControl的一部分,那么我可以看到使用DependencyProperty,然后在OnFooterTitlePropertyChanged事件中,您可以设置

name_of_textbox.Text = FooterTitle;

我认为应该使用OnPropertyChanged方法来指定属性名称,如下所示;

public bool MyProperty
{
    get { return (bool) GetValue(MyPropertyProperty); }
    set { 
              SetValue(MyPropertyProperty, value); 
              OnPropertyChanged("MyProperty"); 
        }
}

https://learn.microsoft.com/en-us/uwp/api/windows.ui.xaml.data.inotifypropertychanged.propertychanged

最新更新