【问题标题】:Issues with ContentDialog and x:BindContentDialog 和 x:Bind 的问题
【发布时间】:2018-06-10 16:18:28
【问题描述】:

我有一个实现INotifyPropertyChangedContentDialog。我有一个 TextBox,其 Text 属性通过 x:Bind 语法绑定到我的代码隐藏上的字符串属性。

如果我编辑TextBox的内容,然后点击ContentDialog中的另一个控件(失去焦点TextBox),然后点击主按钮,由我到的时候主按钮单击事件处理程序的文本属性已更新为 TextBox 控件 = PERFECT 的内容。

但是,如果我更改了 TextBox 的内容,但将其保持在焦点上,然后单击主按钮,则绑定永远不会更新。

这似乎是因为ContentDialog中的内置按钮在触发点击事件处理程序之前没有获得焦点,并且x:Bind只支持LostFocus绑定,这些绑定永远不会更新.

我很惊讶这个大错误的存在。所以我的两个问题是

1) 是否有解决方法

2) 我是否必须放弃 x:Bind 并使用 WPF 样式的 Binding 语法,我可以在绑定本身中更改 UpdateSourceTrigger

我希望另一位 UWP 开发人员遇到过这个问题并知道解决方法

编辑

我创建了一些示例代码来演示这个问题。

页面:

<Page
    x:Class="App1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App1"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Button Content="Open" Click="OpenClick" HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Grid>
</Page>

后面的代码:

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        InitializeComponent();
    }

    private async void OpenClick(object sender, RoutedEventArgs e)
    {
        var dialog = new ContentDialog1();
        await dialog.ShowAsync();
    }
}

内容对话框:

<ContentDialog
    x:Class="App1.ContentDialog1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Title="TITLE"
    PrimaryButtonText="Button1"
    PrimaryButtonClick="ContentDialog_PrimaryButtonClick">

    <Grid>
        <TextBox Text="{x:Bind Path=TestText, Mode=TwoWay}" HorizontalAlignment="Center" VerticalAlignment="Center" MinWidth="100"/>
    </Grid>
</ContentDialog>

后面的内容对话框代码:

public sealed partial class ContentDialog1 : ContentDialog, INotifyPropertyChanged
{
    public ContentDialog1()
    {
        InitializeComponent();
    }

    private string _testText;
    public string TestText
    {
        get => _testText;
        set
        {
            _testText = value;
            OnPropertyChanged(nameof(TestText));
        }
    }

    private void ContentDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
    {
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

我的目标 sdk 版本是:

如果您单击打开内容对话框,输入一些文本,然后单击主按钮 - 如果您在单击处理程序中有断点,您会看到绑定没有更新为您输入的文本

【问题讨论】:

    标签: xaml uwp uwp-xaml


    【解决方案1】:

    好的,我已经对此进行了研究,并在所有 SDK 的背面对此进行了测试以构建 10586。本质上,ContentDialog 已损坏,因为 x:Bind 绑定到 TextBox,因为需要 TextBox 才能失去焦点命令其绑定更新。 在单击处理程序触发,但如果 UWP 不支持隧道事件策略(如 WPF),则无法在按钮按下和硬连线单击处理程序运行之间注入任何类型的事件处理。 结果是x:Bind(不支持UpdateSourceTrigger,除了LostFocus)不能在ContentDialog 中可靠地使用TextBox 控件。

    我在 Microsoft uservoice 上记录了一个错误。

    解决此问题的唯一方法是放弃 x:Bind 并使用支持 UpdateSourceTriggerPropertyChanged 的经典绑定 - 因此允许绑定在单击按钮之前始终是最新的。 但即使这是一个 hack,因为PropertyChangedUpdateSourceTrigger 会在你的setter 中导致不必要的更新——这可能是有问题的。此外,更新INotifyPropertyChanged 中的设置器将为您的所有布局触发许多额外的排列/测量通道。

    唯一真正的解决方案是编写自己的ContentDialog 控件。我很想这样做,但是没有访问这些控件的 Microsoft 源代码,很难知道你是否成功地完成了它

    【讨论】:

      【解决方案2】:

      我无法重现该问题:代码隐藏中的string 属性的设置器始终在ContentDialog_PrimaryButtonClick 之前触发,即使我在焦点仍在TextBox 上时单击主按钮也是如此。我的示例(在 Fall Creators Update 上测试):

      MyContentDialog.xaml

      <Grid>
          <TextBox Text="{x:Bind MyString, Mode=TwoWay}"/>
      </Grid>
      

      MyContentDialog.xaml.cs

      public sealed partial class MyContentDialog : ContentDialog, INotifyPropertyChanged
      {
          private DTO dto;
      
          private string myString;
          public string MyString
          {
              get
              {
                  return myString;
              }
              set
              {
                  myString = value;
                  NotifyPropertyChanged(nameof(MyString));
              }
          }
      
          public MyContentDialog(DTO dto)
          {
              this.InitializeComponent();
      
              this.dto = dto;
              MyString = dto.text;
          }
      
      
          private void ContentDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
          {
              dto.text = MyString;
          }
      
          private void ContentDialog_SecondaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
          {
          }
      
      
          public event PropertyChangedEventHandler PropertyChanged;
          private void NotifyPropertyChanged(string propertyName)
          {
              if (PropertyChanged != null)
                  PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
          }
      }
      

      DTO.cs

      public class DTO
      {
          public string text;
      }
      

      MainPage.xaml.cs

      private async void Page_Loaded(object sender, RoutedEventArgs e)
      {
          DTO dto = new DTO { text = "My text" };
      
          MyContentDialog dialog = new MyContentDialog(dto);
          await dialog.ShowAsync();
      
          await new MessageDialog("My text, after being edited by the user in MyContentDialog: " + dto.text).ShowAsync();
      }
      

      你能分享你的代码吗?您项目的最低版本和目标版本是多少?

      【讨论】:

      • 感谢您的帮助。已经创建了一个显示此问题的代码版本,并包含目标 SDK 信息
      【解决方案3】:

      我刚刚发现我花了很多时间,就像你做的差不多两天失败,如果有空对象绑定到任何必须使用转换器的控件,内容对话框会崩溃我的应用程序。

      我只是在想如何在对话框上放置一个用户控件并查看绑定是否有效。

      让我在这里尝试发布结果。

      如果你想出了其他方法,请告诉我

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-09-10
        • 2016-09-07
        • 1970-01-01
        • 2016-09-20
        • 2018-06-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多