OneWayToSource 绑定在 .NET 4.0 中似乎已损坏

发布于 2024-10-15 05:29:06 字数 1339 浏览 1 评论 0原文

OneWayToSource 绑定在 .NET 4.0 中似乎已损坏

我有一段简单的 Xaml

<StackPanel>
    <TextBox Text="{Binding TextProperty, Mode=OneWayToSource}"/>
    <Button/>
</StackPanel>

我的代码看起来像这样

public MainWindow()
{
    InitializeComponent();
    this.DataContext = this;
}
private string m_textProperty;
public string TextProperty
{
    get
    {
        return "Should not be used in OneWayToSource Binding";
    }
    set
    {
        m_textProperty = value;
    }
}

在 .NET 3.5 中,这可以正常工作。在 TextBox 中放入一些文本,按 Tab 键使其失去焦点,TextProperty 会使用 TextBox 中输入的任何文本进行更新

< strong>在 .NET 4.0 中,如果我在 TextBox 中键入一些文本,然后按 Tab 键使其失去焦点,TextBox 将恢复为TextProperty(意思是“不应在 OneWayToSource Binding 中使用”)。此重读是否旨在用于 .NET 4.0 中的 OneWayToSource 绑定?我只是希望 TextBox 将其值推送到 TextProperty 中,而不是相反。

更新
向这个问题添加赏金,因为这已经成为我的项目中的一个主要不便,我想知道这种情况发生变化的原因。看来 get 是在 Binding 更新源之后调用的。这是 .NET 4.0 中 OneWayToSource 绑定所需的行为吗?

如果是

  • 3.5 中的工作方式有什么问题?
  • 这种新行为在什么情况下更好?

或者这实际上是一个我们希望在未来版本中修复的错误吗?

OneWayToSource Binding seems broken in .NET 4.0

I have this simple piece of Xaml

<StackPanel>
    <TextBox Text="{Binding TextProperty, Mode=OneWayToSource}"/>
    <Button/>
</StackPanel>

And my code behind looks like this

public MainWindow()
{
    InitializeComponent();
    this.DataContext = this;
}
private string m_textProperty;
public string TextProperty
{
    get
    {
        return "Should not be used in OneWayToSource Binding";
    }
    set
    {
        m_textProperty = value;
    }
}

In .NET 3.5 this works as you might except. Put some text in the TextBox, press Tab to make it lose Focus, and the TextProperty updates with whatever text that was entered in the TextBox

In .NET 4.0, if I type some text in the TextBox and then press Tab to make it lose Focus, the TextBox reverts to the value for TextProperty (meaning "Should not be used in OneWayToSource Binding"). Is this re-reading intended for a OneWayToSource Binding in .NET 4.0? I just want the TextBox to push its value into the TextProperty and not the other way around.

Update
Adding a Bounty to this question as this has become a mayor inconvenience in my project and I would like to know the reason that this has changed. It seems that get is called after the Binding has updated the source. Is this the desired behavior for a OneWayToSource Binding in .NET 4.0?

If Yes

  • What was the problem with the way it worked in 3.5?
  • In what scenarios is this new behavior better?

Or is this in fact a bug that we can hope to get fixed in a future release?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

走走停停 2024-10-22 05:29:06

Karl Shifflett 的博客和 @Simpzon 的回答已经介绍了他们添加此功能的原因以及为什么对于始终获得所设置内容的属性来说这不是问题。在您自己的代码中,您始终使用具有正确绑定语义的中间属性,并使用具有所需语义的内部属性。我将中间属性称为“阻塞”属性,因为它阻止 getter 到达您的内部属性。

但是,如果您无权访问要设置属性的实体的源代码并且您想要旧的行为,则可以使用转换器。

这是一个带有 state: 的阻塞转换器

public class BlockingConverter : IValueConverter
{
    public object lastValue;

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return lastValue;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        lastValue = value;
        return value;
    }
}

,您可以将它用于您的示例,如下所示:

<Grid>
    <Grid.Resources>
        <local:BlockingConverter x:Key="blockingConverter" x:Shared="False"/>
    </Grid.Resources>
    <StackPanel>
        <TextBox Text="{Binding TextProperty, Mode=OneWayToSource, Converter={StaticResource blockingConverter}}"/>
        <Button Content="Click"/>
    </StackPanel>
</Grid>

请注意,因为转换器有一个状态,所以每次使用资源时您都需要一个单独的实例,为此我们可以使用 x:资源上的 Shared="False" 属性。

Karl Shifflett's blog and @Simpzon's answer already cover why they added this feature and why it is not a problem for properties that always get what was set. In your own code you always use an intermediate property that has the proper semantics for binding and use an internal property that has the semantics you want. I would call the intermediate property a "blocking" property because it blocks the getter from reaching your internal property.

But in the case where you don't have access to the source code for the entity that you are setting the property on and you want the old behavior, you can use a converter.

Here is a blocking converter with state:

public class BlockingConverter : IValueConverter
{
    public object lastValue;

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return lastValue;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        lastValue = value;
        return value;
    }
}

and you can use it for your example like this:

<Grid>
    <Grid.Resources>
        <local:BlockingConverter x:Key="blockingConverter" x:Shared="False"/>
    </Grid.Resources>
    <StackPanel>
        <TextBox Text="{Binding TextProperty, Mode=OneWayToSource, Converter={StaticResource blockingConverter}}"/>
        <Button Content="Click"/>
    </StackPanel>
</Grid>

Note that because the converter has a state you need a separate instance each time the resource is used and for this we can use the x:Shared="False" attribute on the resource.

始于初秋 2024-10-22 05:29:06

这确实是设计使然。通常它不应该造成麻烦,但我想说,你的属性实现至少是非常规的。
getter 和 setter(访问器)实际上应该不比 get 和 set 做更多的事情,并且每个 get 都应该与最后一个对应的 set 一致。 (抱歉,没有这方面的资料,这就是我所加入的所有开发团队中我们所说的良好公民意识)。

有关该功能的更多详细信息,请参见:http://karlshifflett.wordpress.com/2009/05/27/wpf-4-0-data-binding-change-great-feature/

This is indeed by design. Usually it should not make trouble, but your property implementation is at least unconventional, I would say.
Getters and setters (accessors) should really do not much more than get and set, and each get should be consistent with the last corresponding set. (sorry, no source for this, it's just what we have called good citizenship in all development teams I've been in).

More details about the feature here: http://karlshifflett.wordpress.com/2009/05/27/wpf-4-0-data-binding-change-great-feature/

一杆小烟枪 2024-10-22 05:29:06

错误,绝对是。

如果它是一个“功能”,那么这是一个非常糟糕的功能...

似乎他们在 set() 完成后添加了对 get() 函数的调用,即使在 OneWayToSource 模式下也是如此...任何人都可以解释为什么吗?

另外,感谢您指出这一点,它解释了自从我将项目升级到 .net 4.0 以来我遇到的一个问题,直到现在我都无法解释......

只是旁注:我已经通过使用依赖属性解决了这个问题结尾。

Bug, definitely.

if it's a "feature", it's a very bad one...

it seems they have added a call to the get() function after the set() is done, even in the OneWayToSource mode... can anybody explain why ?

also, thanks for pointing this out, it explains an issue I have had since I upgraded my project to .net 4.0 and that I could not explain until now...

just a side note: I have solved this by using dependency properties in the end.

月竹挽风 2024-10-22 05:29:06

这显然是一个错误。似乎有人至少报告过一次。 https://connect.microsoft.com /VisualStudio/feedback/details/612444/onewaytosource-broken-in-net-4-0

我同意许多其他人的观点,即一种方式应该是一种方式。

我的场景很复杂,并且框架版本之间的功能变化让我非常头疼。

我有一个绑定到属性的文本框。我有一个转换器可以动态更改格式。
EG:我在文本框中输入 EU5,属性得到 EU005。我已将绑定设置为在属性更改时触发,因为我需要在用户键入时在 ViewModel 中进行查找。新的实现会在我键入时更改文本框的值。因此,如果我想输入 EU512,我不能轻易输入,因为文本框文本会不断变化。

我已经尝试了很多事情 - 显式绑定(您决定何时更新以及以何种方式更新)。这也有同样的问题。如果我说 UpdateSource,它会执行此操作,但也会重新读取属性并更改目标。

我尝试了 OneWayToSource 并遇到了同样的问题。我发现没有办法在不对我的虚拟机进行烦人的更改的情况下解决这个问题。唯一的其他方法是删除该字段上的绑定并开始触发事件,这将是可怕的。

如果 MS 使绑定的行为符合其逻辑命名,那么我的问题就会消失。即使是选择退出 .net4 实现并表现为 3.5 的绑定属性也适合我。

有人对我如何解决这个问题有任何建议吗?

This is quite clearly a bug. It seems to have been reported at least once by someone. https://connect.microsoft.com/VisualStudio/feedback/details/612444/onewaytosource-broken-in-net-4-0

I agree with many of the others that one way should be one way period.

My scenario is complicated and having functionality changed between framework versions has caused me a real headache.

I have a textbox bound to a property. I have a converter which changes the format on the fly.
EG: I enter EU5 in the textbox, the property gets EU005. I have got the binding set to trigger on property changed as I need to do lookups within the ViewModel as the user types. The new implementation changes the value of the textbox as I type. So if I wish to type EU512 I couldn't easily as the textbox text would keep changing.

I have tried many thing - Explicit binding (where you decide when to update and which way.) This has the same problem. If I say, UpdateSource, it does, but also then rereads the property and changes the target too.

I tried OneWayToSource and had the same problem. I have found no way to work around this without making annoying changes to my VM. The only other way would be to remove binding on this field and start firing events which would be awful.

If MS made the binding behave as it is logically named then my problem would disappear. Even a property on the binding to opt out of the .net4 implementation and behave as 3.5 would work for me.

Anyone have any suggestions for me on how I can get around this?

爱情眠于流年 2024-10-22 05:29:06

我对这个问题有一个变体,用于双向绑定。我意识到这与正在讨论的问题并不完全相同,但这个答案在搜索时出现在首位,并导致了我的解决方案。希望有人觉得它有帮助。

我的解决方案会阻止重新读取支持属性,但当它被其他源更改时会更新 UI。我的解决方案基于 Rick Sladkey 的答案中的阻塞转换器。

它只是向转换添加一个检查,以查看 lastValue 字段是否会转换为相同的后备存储值。如果不是,则后备存储值必须已从另一个源更改,并且应更新 UI。

public class MyConverter : IValueConverter
{
    public object lastValue;

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (LastValue != null && MyConvertBack(LastValue).Equals(value))
            return lastValue;
        else
            return MyConvert(value);

    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        lastValue = value;
        return MyConvertBack(value);
    }

    private object MyConvertBack(Object value)
    {
        //Conversion Code Here
    }

    private object MyConvert(Object value)
    {
        //Conversion Code Here
    }
}

在我的特定用例中,我将长度和尺寸后缀存储在文本框中(10m、100mm 等)。转换器将其解析为双精度值或添加后缀(取决于转换方向)。如果没有转换器,它会在文本框的每次更新上添加后缀。尝试输入“10”将导致“1m0”,因为转换器将在第一次击键后运行。

I had a variation of this issue for a two way binding. I realise that this is not exactly the same as the problem being discussed but this answer came up top while searching and it lead to my solution. Hope someone finds it helpful.

My solution blocks the re-read of the backing property but will update the UI when it is changed by some other source. I based my solution on the blocking converter in Rick Sladkey's answer.

It just adds a check to the convert to see if the lastValue field would convert to the same backing store value. If not, the backing store value must have changed from another source and the UI should be updated.

public class MyConverter : IValueConverter
{
    public object lastValue;

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (LastValue != null && MyConvertBack(LastValue).Equals(value))
            return lastValue;
        else
            return MyConvert(value);

    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        lastValue = value;
        return MyConvertBack(value);
    }

    private object MyConvertBack(Object value)
    {
        //Conversion Code Here
    }

    private object MyConvert(Object value)
    {
        //Conversion Code Here
    }
}

In my particular usecase for this I had a length and dimension suffix stored in a textbox (10m, 100mm etc). The converter parsed this to a double value or added the suffix (depending on direction of conversion). Without the converter it would add a suffix on each update of the textbox. Trying to type '10' would result in '1m0' as the converter would run after the first key stroke.

星星的軌跡 2024-10-22 05:29:06

这是 .NET 4.0 中 OneWayToSource 绑定所需的行为吗?

是的。这样做是为了让开发人员能够更改提供的值,而无需使用笨拙的转换器。

它在 3.5 中的工作方式有什么问题?

没问题。 3.5 中的工作方式不允许更正提供的值。

这种新行为在什么情况下更好?

当您需要更正提供的值时。如果你不需要它,那么你应该只编写正确的属性的 getter 和 setter。

public string TextProperty
{
    get;
    set;
}

但是,正如我所看到的,将 UpdateSourceTrigger 更改为“PropertyChanged”可以防止重新读取值(因此您可以保留旧的属性声明):

<StackPanel>
    <TextBox Text="{Binding TextProperty, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}"/>
    <Button/>
</StackPanel>

    private string m_textProperty;
    public string TextProperty
    {
        get
        {
            return "Should not be used in OneWayToSource Binding";
        }
        set
        {
            m_textProperty = value;
        }
    }

Is this the desired behavior for a OneWayToSource Binding in .NET 4.0?

Yes. This is done for developer's ability to change provided value without clumsy converters.

What was the problem with the way it worked in 3.5?

No problem. The way it worked in 3.5 didn't allow to correct provided values.

In what scenarios is this new behavior better?

When you need to correct provided values. If you don't need it, then you should just write correct property's getter and setter.

public string TextProperty
{
    get;
    set;
}

However, as I can see, changing UpdateSourceTrigger to "PropertyChanged" preserves values from being reread (so you could leave old property declaration):

<StackPanel>
    <TextBox Text="{Binding TextProperty, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}"/>
    <Button/>
</StackPanel>

    private string m_textProperty;
    public string TextProperty
    {
        get
        {
            return "Should not be used in OneWayToSource Binding";
        }
        set
        {
            m_textProperty = value;
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文