Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/heroku/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Xaml ContentDialog和x:Bind的问题_Xaml_Uwp_Uwp Xaml - Fatal编程技术网

Xaml ContentDialog和x:Bind的问题

Xaml ContentDialog和x:Bind的问题,xaml,uwp,uwp-xaml,Xaml,Uwp,Uwp Xaml,我有一个ContentDialog,它实现了INotifyPropertyChanged。我有一个TextBox,它的文本属性通过x:Bind语法绑定到我代码后面的字符串属性 如果我编辑文本框的内容,然后单击内容对话框中的另一个控件(失去对文本框的关注),然后单击主按钮,当我到达主按钮click事件处理程序时,文本属性已经用TextBoxcontrol=PERFECT的内容更新 但是,如果我更改了文本框的内容,但将其保持在焦点位置,然后单击主按钮,则绑定将永远不会更新 这样做的原因似乎是因为Co

我有一个
ContentDialog
,它实现了
INotifyPropertyChanged
。我有一个
TextBox
,它的文本属性通过
x:Bind
语法绑定到我代码后面的字符串属性

如果我编辑
文本框的内容
,然后单击
内容对话框
中的另一个控件(失去对
文本框
的关注),然后单击主按钮,当我到达主按钮click事件处理程序时,文本属性已经用
TextBox
control=PERFECT的内容更新

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

这样做的原因似乎是因为
ContentDialog
中的内置按钮在触发其click EventHandler之前不会获得焦点,并且由于
x:Bind
仅支持
LostFocus
绑定,这些绑定将永远不会更新

我对这个大虫子的存在感到震惊。所以我的两个问题是

1) 有解决办法吗

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

我希望另一个UWP开发人员已经遇到了这一点,并知道一个解决办法

编辑

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

第页:

内容对话框:

<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>
我的目标sdk版本是:


如果单击“打开内容”对话框,请输入一些文本,然后单击主按钮-如果单击处理程序中有一个断点,您将看到绑定没有使用输入的文本更新。我无法重现该问题:代码隐藏中的
字符串
属性的setter总是在
内容对话框\u主按钮单击之前启动,即使在焦点仍在
文本框上时单击主按钮
。我的样本(在秋季创作者更新中测试):

MyContentDialog.xaml

DTO.cs

MainPage.xaml.cs


你能分享你的代码吗?您的项目的最小版本和目标版本是什么?

好的,我已经研究了这个问题,并在所有SDK的back to build 10586上进行了测试。本质上,
ContentDialog
对于
x:Bind
TextBox
的绑定被破坏,因为
TextBox
需要失去焦点才能更新其绑定。 我已经尝试了很多方法,包括在点击处理程序触发之前,在加载的
上遍历视觉树,向隐藏按钮添加额外的处理程序,并尝试强制它们聚焦(从而从任何
文本框中移除焦点,并触发绑定更新),但不支持隧道事件策略的UWP(与WPF类似),不可能在按钮按下和硬连线的click处理程序之间插入任何类型的事件处理。
结果是
x:Bind
(除了
LostFocus
,它不支持
UpdateSourceTrigger
)无法在
ContentDialog
中可靠地使用
TextBox
控件

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

解决此问题的唯一方法是放弃
x:Bind
,使用支持
PropertyChanged
UpdateSourceTrigger
的经典绑定,从而允许绑定在单击按钮之前始终是最新的。 但即使这样,这也是一种黑客行为,因为
PropertyChanged
UpdateSourceTrigger
将导致设置程序中不必要的更新,这可能会有问题。此外,在
INotifyPropertyChanged
中更新设置程序将为所有布局触发多轮额外的排列/测量过程


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

我刚刚想出来,我花了很多时间,就像您做的一样,几乎两天都失败了,ContentDialog崩溃了y应用程序如果有空对象绑定到任何控件,都必须使用转换器

我正在考虑在对话框上放置一个usercontrol,看看绑定是否有效

让我试着把结果贴在这里


如果您找到了其他方法,请告诉我

谢谢您的帮助。我已经创建了一个显示此问题的代码版本,并包含了目标SDK信息
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));
    }
}
<Grid>
    <TextBox Text="{x:Bind MyString, Mode=TwoWay}"/>
</Grid>
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));
    }
}
public class DTO
{
    public string text;
}
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();
}