当前位置: 首页 > 知识库问答 >
问题:

SseltedIndex与OneWayToSource绑定不触发

孔波
2023-03-14

我对特定的xaml数据绑定有问题。我有两个列表框(主详细信息,因此列表框的IsSynchronizedWithCurrentItem设置为true)。我想让我的viewmodel知道详细信息列表框上的选定项何时更改:我在viewmodel类上创建了一个int属性(即,我们可以将此属性称为SelInd),并通过以下方式在详细信息viewmodel上绑定:

    SelectedIndex="{Binding Mode=OneWayToSource, Path=SelInd}"

我在运行时没有错误/异常,但是绑定不会触发:当选择的项目更改时,我的视图模型的属性不会更新。如果我将绑定模式更改为双向,一切都可以正常工作,但这不是我需要的。我需要它与OneWayToSource一起工作(顺便说一句,如果我将选择项绑定到选择值属性,同样的非工作行为也适用)。

为什么这些绑定不会使用OneWayToSource触发?

这里有一个更完整的代码示例,只是为了让事情更清楚: EDIT:我不能显示真正的代码(NDA),但我会在这里展示一些足够简单和相似的东西(页面的数据上下文是PageViewModel类的一个实例,稍后会解释)我只需要我的视图模型类的SelInd属性总是反映第二个列表框中的选择索引的值。我已经找到了其他方法来做到这一点(代码背后的事件处理程序或附加行为),但现在我只是好奇为什么它不能与OneWayToSource绑定一起工作。

<Page>
    <ContentControl x:Name="MainDataContext">
        <Grid DataContext={Binding Path=Masters}>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />

            </Grid.ColumnDefinitions>

            <ListBox Grid.Column="0"
                SelectionMode="Single"                           
             IsSynchronizedWithCurrentItem="True"
             ItemsSource="{Binding }">
                <ListBox.ItemContainerStyle>
            ...
            </ListBox.ItemContainerStyle>
            <ListBox.ItemTemplate>
                <DataTemplate>
                ....
                    </DataTemplate>
            </ListBox.ItemTemplate>
            </ListBox>

            <ListBox Grid.Column="1"
                SelectionMode="Single"                           
              SelectedIndex="{Binding Mode=OneWayToSource,  ElementName=MainDataContext,Path=DataContext.SelInd}"
             IsSynchronizedWithCurrentItem="True"
             ItemsSource="{Binding Path=Details}">
                <ListBox.ItemContainerStyle>
            ...
            </ListBox.ItemContainerStyle>
            <ListBox.ItemTemplate>
                <DataTemplate>
                ....
                    </DataTemplate>
            </ListBox.ItemTemplate>
            </ListBox>
        </Grid>
    </ContentControl>
</Page>

下面是视图模型类的草图

public class PageViewModel{
    public ObservableCollection<MasterClass> Masters {get;set;}

    public int SelInd {get;set;}

    ....
}

这是MasterClass,它只包含一个名字和一个细节列表

public class MasterClass{
    public ObservableCollection<DetailsClass> Details {get;set;}

    public String MasterName {get;set;}

    ....
}

共有2个答案

贡念
2023-03-14

嗯,我找到了一个让它工作的方法。我刚刚删除了数据上下文“间接”,这样我就不必在绑定中使用ElementName,它开始工作了。工作中的xaml示例是:

<Page>
    <ContentControl >
        <Grid >
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />

            </Grid.ColumnDefinitions>

            <ListBox Grid.Column="0"
                SelectionMode="Single"                           
             IsSynchronizedWithCurrentItem="True"
             ItemsSource="{Binding Masters }">
                <ListBox.ItemContainerStyle>
            ...
            </ListBox.ItemContainerStyle>
            <ListBox.ItemTemplate>
                <DataTemplate>
                ....
                    </DataTemplate>
            </ListBox.ItemTemplate>
            </ListBox>

            <ListBox Grid.Column="1"
                SelectionMode="Single"                           
              SelectedIndex="{Binding Mode=OneWayToSource,  Path=SelInd}"
             IsSynchronizedWithCurrentItem="True"
             ItemsSource="{Binding Path=Masters/Details}">
                <ListBox.ItemContainerStyle>
            ...
            </ListBox.ItemContainerStyle>
            <ListBox.ItemTemplate>
                <DataTemplate>
                ....
                    </DataTemplate>
            </ListBox.ItemTemplate>
            </ListBox>
        </Grid>
    </ContentControl>
</Page>

现在,如果有人确切地知道为什么使用ElementName的绑定不起作用,我想知道:)

海岳
2023-03-14

我认为在你的情况下,你必须使用单向模式。默认情况下,您使用了双向模式

引用MSDN中关于双向的two-way

双向绑定会导致对源属性或目标属性的更改自动更新另一个属性。这种类型的绑定适用于可编辑表单或其他完全交互的UI场景。大多数属性默认为单向绑定,但一些依赖项属性(通常是用户可编辑控件的属性,例如TextBox的Text属性和CheckBox的IsChecked属性)默认为双向绑定。确定依赖项属性在默认情况下是单向绑定还是双向绑定的编程方法是,使用GetMetadata获取属性的属性元数据,然后检查BindsTwoWayByDefault属性的布尔值。

模式单向,即您需要的

OneWay绑定会使源属性的更改自动更新目标属性,但对目标属性的更改不会传播回源属性。如果绑定的控件是隐式只读的,这种类型的绑定是合适的。例如,您可以绑定到源,如股票代码,或者您的目标属性没有提供用于进行更改的控制接口,如表的数据绑定背景颜色。如果不需要监控目标属性的更改,使用OneWay绑定模式可以避免TwoWay绑定模式的开销。

模式OneWayToSource

OneWayToSource是单向绑定的反向;当目标属性更改时,它会更新源属性。一个示例场景是,如果只需要从UI重新评估源值。

下面是一张更好地理解以下内容的图表:

好吧,那我给你看一个对我有用的例子。也许它会对你有用。

XAML

<Window x:Class="SelectedIndexHelp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:SelectedIndexHelp"
    Title="MainWindow" Height="350" Width="525"
    ContentRendered="Window_ContentRendered"
    WindowStartupLocation="CenterScreen">

    <Window.Resources>
        <local:SelectedIndexClass x:Key="SelectedIndexClass" />
    </Window.Resources>

    <Grid DataContext="{StaticResource SelectedIndexClass}">
        <ListBox x:Name="MyListBox" 
                 BorderThickness="1" 
                 Width="200" Height="200"
                 BorderBrush="#CE5E48" 
                 DisplayMemberPath="Name" 
                 Background="AliceBlue" 
                 SelectedIndex="{Binding MySelectedIndex, Mode=OneWayToSource}" />

        <Label Name="SelectedIndex" VerticalAlignment="Top"
               Content="{Binding MySelectedIndex}"
               ContentStringFormat="SelectedIndex: {0}"
               Width="100" Height="30" Background="Lavender" />
    </Grid>
</Window>

后面的代码

public partial class MainWindow : Window
{
    public class Person
    {
        public string Name
        {
            get;
            set;
        }

        public int Age
        {
            get;
            set;
        }            
    }

    private ObservableCollection<Person> DataForListBox = new ObservableCollection<Person>();

    public MainWindow()
    {
        InitializeComponent();
    }

    private void Window_ContentRendered(object sender, EventArgs e)
    {
        DataForListBox.Add(new Person()
        {
            Name = "Sam",
            Age = 22,
        });

        DataForListBox.Add(new Person()
        {
            Name = "Nick",
            Age = 21,
        });

        DataForListBox.Add(new Person()
        {
            Name = "Cris",
            Age = 25,
        });

        DataForListBox.Add(new Person()
        {
            Name = "Josh",
            Age = 36,
        });

        DataForListBox.Add(new Person()
        {
            Name = "Max",
            Age = 32,
        });

        DataForListBox.Add(new Person()
        {
            Name = "John",
            Age = 40,
        });

        MyListBox.ItemsSource = DataForListBox;
        MyListBox.Focus();
    }
}

public class SelectedIndexClass 
{
    private int? mySelectedIndex = 0;

    public int? MySelectedIndex
    {
        get
        {
            return mySelectedIndex;
        }

        set
        {
            mySelectedIndex = value;
        }
    }
}

输出

在本例中,有一类数据-Person,这些数据用于列表框。类SelectedIndexClassDataContext),它包含属性MySelectedIndex,这是绑定OneWayToSource的参数。

编辑:我很高兴你解决了这个问题。我会试着通过他们的例子解释,为什么你不使用ElementName案例。

假设我们有以下代码:

<ContentControl x:Name="MainDataContext">
    <Grid x:Name="MainGrid" DataContext="{StaticResource SelectedIndexClass}">
        <ListBox x:Name="MyListBox" 
                    BorderThickness="1" 
                    Width="200" Height="200"
                    BorderBrush="#CE5E48" 
                    DisplayMemberPath="Name" 
                    Background="AliceBlue" 
                    SelectedIndex="{Binding Path=DataContext.MySelectedIndex, Mode=OneWayToSource, ElementName=MainDataContext}" />

        <Label Name="SelectedIndex" VerticalAlignment="Top"
                Content="{Binding MySelectedIndex}"
                ContentStringFormat="SelectedIndex: {0}"
                Width="100" Height="30" Background="Lavender" />
    </Grid>
</ContentControl>

正如你可能理解的那样,这是行不通的。

DataContext设置在可视化树的特定节点上,下面(可视化树中)的所有项都将继承它。这意味着DataContext将自Grid和可视化树下面起工作。因此,以下代码将起作用:

<ContentControl x:Name="MainDataContext">
    <Grid x:Name="MainGrid" DataContext="{StaticResource SelectedIndexClass}">
        <ListBox x:Name="MyListBox" 
                    BorderThickness="1" 
                    Width="200" Height="200"
                    BorderBrush="#CE5E48" 
                    DisplayMemberPath="Name" 
                    Background="AliceBlue" 
                    SelectedIndex="{Binding Path=DataContext.MySelectedIndex, Mode=OneWayToSource, ElementName=MainGrid}" />

        <Label Name="SelectedIndex" VerticalAlignment="Top"
                Content="{Binding MySelectedIndex}"
                ContentStringFormat="SelectedIndex: {0}"
                Width="100" Height="30" Background="Lavender" />
    </Grid>
</ContentControl>

而且,如果点的名称MyListBox,它也会工作。通常,当设置DataContext时,元素名称会传递。

 类似资料:
  • 如何指定用户点击通知包时要使用的意图?

  • 我正在用Web API5构建Web服务。我正在通过扩展IModelBinder接口来实现自定义模型绑定器,以将复杂类型映射为操作的参数。装订部分工作正常。但不会进行模型验证。ModelState.IsValid始终为true。 如果我显式调用Validate()或使用[FromUri]属性,则ModelState.isValid设置正确。 我应该在模型绑定器内实现验证部分。如果是,我应该如何实现?

  • 静态绑定还是动态绑定? 这显示了什么样的多态性?

  • 我在写一个函数,需要返回多个变量,其中一个是位集。然后我遇到了一些奇怪的编译错误。 我尝试了不同的编译器,它们都会产生错误,尽管消息不同。 我试着googling了一下,似乎和公共和私有继承有关。但我认为它不应该以任何方式影响这段代码。 简化代码(C 17)如下所示: 如果我移除方括号(即移除结构化绑定并使用普通自动),它就会工作。 错误消息如下: source.cpp:在函数int main()

  • 我已经审阅了Microsoft提供的关于触发器的文档。[https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-storage-blob-trigger?tabs=python][1] 事实上,在Azure函数中使用参数允许我们检索blob和一些属性(),我们还可以使用函数读取字节,但是我们如何将字节转换为

  • 关于在物联网场景中使用EventHub的Azure功能,我有几个问题。 EventHub有分区。通常来自特定设备的消息会发送到同一个分区。Azure Function的实例如何分布在EventHub分区中?它是基于性能的吗?如果Azure Function的一个实例设法处理来自所有分区的事件,那么这就足够了,否则每个EventHub分区可能会有一个Azure Function的实例? 读取偏移量呢