首页 文章

更改DataContext不会更新列表字段

提问于
浏览
1

我创建了一个新的TextBlock类,它具有ItemsSource属性并将ItemsSource转换为“Run”对象:

public class MultiTypeDynamicTextBlock : TextBlock
{
    public interface ISection
    {
        Inline GetDisplayElement();
    }

    public class TextOption : ISection
    {
        private Run mText;

        public TextOption(string aText)
        {
            mText = new Run();
            mText.Text = aText.Replace("\\n", "\n");
        }

        public Inline GetDisplayElement()
        {
            return mText;
        }
    }

    public class LineBreakOption : ISection
    {
        public Inline GetDisplayElement()
        {
            return new LineBreak();
        }

        public ISection Clone()
        {
            return new LineBreakOption();
        }
    }

    public class ImageOption : ISection
    {
        private InlineUIContainer mContainer;

        public ImageOption(string aDisplay)
        {
            Image lImage;
            lImage = new Image();
            lImage.Source = new BitmapImage(new Uri(Environment.CurrentDirectory + aDisplay));
            lImage.Height = 15;
            lImage.Width = 15;
            mContainer = new InlineUIContainer(lImage);
        }

        public Inline GetDisplayElement()
        {
            return mContainer;
        }
    }

    public static readonly DependencyProperty ItemsSourceProperty =
        DependencyProperty.Register("ItemsSource", typeof(ObservableCollection<ISection>), typeof(MultiTypeDynamicTextBlock),
        new UIPropertyMetadata(new ObservableCollection<ISection>(),
        new PropertyChangedCallback(SetContent)));

    public ObservableCollection<ISection> ItemsSource
    {
        get
        {
            return GetValue(ItemsSourceProperty) as ObservableCollection<ISection>;
        }
        set
        {
            if (ItemsSource != null)
                ItemsSource.CollectionChanged -= CollectionChanged;
            SetValue(ItemsSourceProperty, value);
            SetContent();
            ItemsSource.CollectionChanged += CollectionChanged;
        }
    }

    private void CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        SetContent();
    }

    private static void SetContent(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        DependencyObject lParent = d;
        MultiTypeDynamicTextBlock lPanel = lParent as MultiTypeDynamicTextBlock;
        if (lPanel != null)
        {
            lPanel.ItemsSource = e.NewValue as ObservableCollection<ISection>;
        }
    }

    private void SetContent()
    {
        if (ItemsSource != null)
        {
            Inlines.Clear();
            foreach (ISection lCurr in ItemsSource)
            {
                Inlines.Add(lCurr.GetDisplayElement());
            }
        }
    }

如果我将ItemsSource直接绑定到DataContext,它可以工作 . 但是如果我将它绑定到在运行时更改的对象(例如ListBox上的SelectedItem),则在选择新项时它不会更新文本 .

<StackPanel>
    <ListBox x:Name="TheList" ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Title}"/>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    <StackPanel DataContext="{Binding ElementName=TheList, Path=SelectedItem}">
        <TextBlock Text="{Binding Title}" FontSize="20"/>
        <local:MultiTypeDynamicTextBlock ItemsSource="{Binding Items}"/>
    </StackPanel>
</StackPanel>

有什么理由吗?

2 回答

  • 0

    在您的示例中, SelectedItem 是否有两个属性 TitleItems ?或者 Items 是您的viewmodel中的属性?如果答案是后者,那么你可以在下面找到解决方案 .

    我不试试看 . 如果您的意思是未设置自定义控件上的 ItemsSource ,则必须将 XAML 指向正确的方向 . 如果这是您想要实现的目标,您可以在下面找到解决方案 . 我所做的是用这行代码将编译器指向正确的源代码:

    ItemsSource="{Binding DataContext.Items, RelativeSource={RelativeSource AncestorType=Window}}"
    

    在这里,您说编译器可以在窗口的 DataContext (或任何可以找到 property 的控件)中找到 Binding property .

    <StackPanel>
            <ListBox x:Name="TheList" ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Title}"/>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
            <StackPanel DataContext="{Binding ElementName=TheList, Path=SelectedItem}">
                <TextBlock Text="{Binding Title}" FontSize="20"/>
                <local:MultiTypeDynamicTextBlock ItemsSource="{Binding DataContext.Items, RelativeSource={RelativeSource AncestorType=Window}}"/>
            </StackPanel>
        </StackPanel>
    

    希望这有帮助 .


    EDIT

    当我从 ListBox 中选择另一个时, title property 会发生变化 . 如果 Items 设置为新的 ObservableCollection ,当 SelectedItem 更改时,是否为 Items 调用 OnPropertyChanged event

    OnPropertyChanged("Items");
    
  • 0

    谢谢您的帮助 . 我设法通过更新MultiTypeDynamicTextBlock来解决这个问题,如下所示:

    public class MultiTypeDynamicTextBlock : TextBlock
    {
        public interface ISection
        {
            Inline GetDisplayElement();
    
            ISection Clone();
        }
    
        public class TextOption : ISection
        {
            private Run mText;
    
            public TextOption(string aText)
            {
                mText = new Run();
                mText.Text = aText.Replace("\\n", "\n");
            }
    
            public Inline GetDisplayElement()
            {
                return mText;
            }
    
            public ISection Clone()
            {
                return new TextOption(mText.Text);
            }
        }
    
        public class LineBreakOption : ISection
        {
            public Inline GetDisplayElement()
            {
                return new LineBreak();
            }
    
            public ISection Clone()
            {
                return new LineBreakOption();
            }
        }
    
        public class SectionList
        {
            private ObservableCollection<ISection> mList;
    
            public Action CollectionChanged;
    
            public ObservableCollection<ISection> Items
            {
                get
                {
                    ObservableCollection<ISection> lRet = new ObservableCollection<ISection>();
                    foreach (ISection lCurr in mList)
                    {
                        lRet.Add(lCurr.Clone());
                    }
                    return lRet;
                }
            }
    
            public int Count { get { return mList.Count; } }
    
            public SectionList()
            {
                mList = new ObservableCollection<ISection>();
            }
    
            public void Add(ISection aValue)
            {
                mList.Add(aValue);
            }
    
            public SectionList Clone()
            {
                SectionList lRet = new SectionList();
                lRet.mList = Items;
                return lRet;
            }
        }
    
        public MultiTypeDynamicTextBlock()
        {
    
        }
    
        public static readonly DependencyProperty ItemsCollectionProperty =
            DependencyProperty.Register("ItemsCollection", typeof(SectionList), typeof(MultiTypeDynamicTextBlock),
                new UIPropertyMetadata((PropertyChangedCallback)((sender, args) =>
                {
                    MultiTypeDynamicTextBlock textBlock = sender as MultiTypeDynamicTextBlock;
                    SectionList inlines = args.NewValue as SectionList;
    
                    if (textBlock != null)
                    {
                        if ((inlines != null) && (inlines.Count > 0))
                        {
                            textBlock.ItemsCollection.CollectionChanged += textBlock.ResetInlines;
                            textBlock.Inlines.Clear();
                            foreach (ISection lCurr in textBlock.ItemsCollection.Items)
                            {
                                textBlock.Inlines.Add(lCurr.GetDisplayElement());
                            }
                        }
                        else
                        {
                            inlines = new SectionList();
                            inlines.Add(new TextOption("No value set"));
                            textBlock.ItemsCollection = inlines;
                        }
                    }
                })));
    
        public SectionList ItemsCollection
        {
            get
            {
                return (SectionList)GetValue(ItemsCollectionProperty);
            }
            set
            {
                SectionList lTemp;
                if (value == null)
                {
                    lTemp = new SectionList();
                    lTemp.Add(new TextOption("No value set for property"));
                }
                else
                {
                    lTemp = value;
                }
                SetValue(ItemsCollectionProperty, lTemp);
            }
        }
    
        private void ResetInlines()
        {
            Inlines.Clear();
            foreach (ISection lCurr in ItemsCollection.Items)
            {
                Inlines.Add(lCurr.GetDisplayElement());
            }
        }
    }
    

    并且我将Binded的字段更新为MultiTypeDynamicTextBlock.SectionList类型

    只要我使用副本(克隆)它正在工作,由于某种原因,当我不克隆它从列表中的显示删除值,如果有人知道为什么我会喜欢学习但我设法绕过它 . 窗口的XAML是:

    <StackPanel>
        <ListBox x:Name="TheList" ItemsSource="{Binding GeneralItems}" SelectedItem="{Binding SelectedItem}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel>
                        <TextBlock Text="{Binding Title}" FontSize="20"/>
                        <local:MultiTypeDynamicTextBlock ItemsCollection="{Binding Items}" Margin="20,0,0,0"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <StackPanel DataContext="{Binding GeneralItems, Path=SelectedItem}">
            <TextBlock Text="{Binding Title}" FontSize="20"/>
            <local:MultiTypeDynamicTextBlock DataContext="{Binding Items}" ItemsCollection="{Binding}" Margin="20,0,0,0"/>
        </StackPanel>
    </StackPanel>
    

相关问题