C# WPF 我无法进行私有更新,但 public 会

C# WPF I cannot get private to update but public will

对此我很是疑惑,搜索了也没有找到答案。我确定我没有正确理解某些东西。你能给我解释一下吗?

我有一个视图和一个视图模型。在视图中我有一个 Textblock

<TextBlock 
            Grid.Row="4" 
            Grid.Column="5"  
            Grid.ColumnSpan="3"
            IsEnabled="{Binding Enable, Mode=OneWay}"
            Margin="5,10,5,10">  
          
            <Run Text="File: "/>
            <Run Text="{Binding FilePathName}"/>
            
        </TextBlock>

在我的视图顶部

d:DataContext="{d:DesignInstance d:Type=viewModels:MainWindowViewModel}"

代码后面我也加了

public MainWindow()
        {
            InitializeComponent();
            DataContext = new MainWindowViewModel();
        }

我不想在此处添加 DataContext,但一开始它似乎可以正常工作,但现在我不确定是否需要它,我将尝试删除它。

我想我理解这部分,View 中的数据将从 ViewModel 中名为 FilePathName 的项目中刷新。

现在在视图模型中,我为 FilePathName 创建了“get and set”:

private string _filepathname;

        public string FilePathName
        {
            get => _filepathname;
            set
            {
              if (_filepathname != value) 
              {
                _filepathname = value; 
                OnPropertyChanged();
              }
            }
        }

现在我的理解肯定有点模糊了。我认为在 ModelView 中我将只使用私有字符串。这意味着当我像这样更改它的值时:

_filepathname = “MyNewName”;

然后 PropertyChanged 将看到此更改并将通过 public FilePathName 更新视图。但是,如果我使用 FileOpenDialog 并打开一个文件,然后说

if (openFileDialog.FileName != "")
            {
                _filepathname = openFileDialog.FileName;
                ProcessFile();
            }

我在这里使用的是私有的,但它永远不会更新。如果我在“获取和设置”中放置一个断点,我们永远不会去那里,所以 UI 永远不会更新。

但是我在 ProcessFile() 中使用

StreamReader sr = new StreamReader(_filepathname);

我确实读到了正确的文件。我可以理解,因为它也是私有的。但是……如果我现在将 private 更改为 public 如下

if (openFileDialog.FileName != "")
            {
                FilePathName = openFileDialog.FileName;
                ProcessFile();
            }

我现在更新 UI 并打开正确的文件进行阅读。似乎有时我需要使用 private 有时 public 才能使其工作。为什么?

第二个问题是为什么 isEnabled 似乎不适用于 TextBlock。我让它在按钮和文本框上工作。我在 TextBlock 中使用它如下,您可以在上面进一步查看它。

IsEnabled="{Binding Enable, Mode=OneWay}"

感谢所有帮助。

这不是那样的。 如果是,为什么我们需要属性?

这个:

myString = "new value" ONLY 给变量赋值。就这样。当您使用 属性 执行此操作时,将调用 属性 setter,因此:

if(myString != value)
{
  myString = value; //new value will be assigned to variable
  OnPropertyChanged(); //property changed will be called
}

当你给变量赋值时,你就可以读取它,这就是发生的事情。 该变量称为“支持字段”。它在那里是因为必须有一些变量来存储一个值。如果你这样声明 属性:

public string MyString {get; set;}

在幕后,编译器还创建了这样的支持字段,最后它的工作方式如下:

string __myString;
public string MyString
{
  get {return __myString;}
  set {__myString = value;}
}

所以,如您所见,这只是一种合成糖。如果你想获得更多的属性(比如 call 属性 changed),你必须自己创建这样的 bakcing 字段。

此外,属性 本身不存储任何值。把它想象成一种方法。实际上有两种方法 - 一种是将值赋给变量,另一种是 returns 值:

public void SetMyString(string value)
{
  myString = value;
}

public string GetMyString()
{
  return myString;
}

因为属性atall也是某种合成糖

所以总结一下:

string myString;
public string MyString
{
  get {return myString;}
  set
  {
      if(myString != value)
      {
         myString = value;
         OnPropertyChanged();
      }
  }
}

///

myString = "NewValue"; //<-- only assigns value to variable myString
MyString = "NewValue"; //<-- assings value to variable myString AND calls OnPropertyChanged - because that's how you property setter looks like.

您的视图和视图模型是两个不同的类。 当您更改视图模型的私有字段时,您的视图无法知道是否未收到通知。在 属性 setter 中调用 OnPropertyChanged() 时通知视图。修改字段时不会调用 属性 setter。阅读 了解更多详情。

要回答你的第二个问题,IsEnabled 不是你正在寻找的 属性,因为它禁用了 UI 元素,但没有隐藏它。您需要为此更改可见性 属性(使用转换器)。

以下是我的做法(有其他简化):

<!-- in application or control resources -->
<BooleanToVisibilityConverter x:Key="BooleanToVisibility" />

<TextBlock Grid.Row="4" 
           Grid.Column="5"  
           Grid.ColumnSpan="3"
           Text="{Binding FilePathName, StringFormat=File: {0}}"
           Visibility="{Binding Enable, Mode=OneWay, Converter={StaticResource BooleanToVisibility}}"
           Margin="5,10"/>