C# WPF 我不能私下更新,但公众会

Posted

技术标签:

【中文标题】C# WPF 我不能私下更新,但公众会【英文标题】:C# WPF I cannot get private to update but public will 【发布时间】:2022-01-17 15:05:20 【问题描述】:

我对此感到非常困惑并且已经搜索但找不到答案。我确定我没有正确理解某些内容。你能给我解释一下吗?

我有一个视图和一个视图模型。在视图中我有一个文本块

<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 创建了“获取和设置”:

private string _filepathname;

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

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

_filepathname = “MyNewName”;

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

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

我在这里使用私人,但这永远不会更新。如果我在“get and set”中设置断点,我们永远不会去那里,所以 UI 永远不会更新。

但是我在 ProcessFile() 中使用

StreamReader sr = new StreamReader(_filepathname);

我确实阅读了正确的文件。这我可以理解,因为它也是私人的。但是……如果我现在将私有更改为公开,如下所示

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

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

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

IsEnabled="Binding Enable, Mode=OneWay"

感谢所有帮助。

【问题讨论】:

“IsEnabled 似乎不适用于 TextBlock”是什么意思? 如果 IsEnabled 为真,我希望看到文本,但如果为假,我不希望看到文本。 Using Properties (C# Programming Guide). 【参考方案1】:

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

这个:

myString = "new value" 仅将值分配给变量。就这样。当您使用属性执行此操作时,将调用属性设置器,因此:

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;

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

更重要的是,属性本身不存储任何值。把它想象成一种方法。实际上有两种方法 - 一种为变量赋值,另一种返回值:

public void SetMyString(string value)

  myString = value;


public string GetMyString()

  return myString;

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

总结一下:

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.

【讨论】:

常用术语是“backing field”。 你说得对,我会更新的。 非常感谢,这是我见过的最好的解释,对我来说也很完美。它帮助我理解其他人告诉我的魔力。非常感谢您花时间解释它。【参考方案2】:

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

要回答您的第二个问题,IsEnabled 不是您要查找的属性,因为它会禁用 UI 元素,但不会隐藏它。您需要为此更改 Visibility 属性(使用转换器)。

我会这样做(还有其他简化):

<!-- 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"/>

【讨论】:

感谢您向我解释这一点。我认为我需要研究转换器的整个主题,因为它们看起来非常有用。

以上是关于C# WPF 我不能私下更新,但公众会的主要内容,如果未能解决你的问题,请参考以下文章

多线程任务更新 1 个进度条 - UI C# WPF

C#微信公众号开发

C#微信公众号开发 -- 用户关注之后自动回复

C# WPF 一个设计界面

C# WPF 一个设计界面

公众号白名单怎么设置