更新ObservableCollecttion对象属性已更改 [英] Update ObservableCollecttion on objects property changed

查看:194
本文介绍了更新ObservableCollecttion对象属性已更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

希望有人可以帮助我。我正在创建一个用于编辑图像的Silverlight应用程序。用户具有包含包含元素的层的项目。 (元素是文本和图像元素)。



我有一个代表项目的类。它包含一个ObservableCollection,每个Layer都有一个ObservableCollection。元素是一个抽象类。有一个TextElement和ImageElement类继承自Element。



我的问题是当我更改集合中的元素时,UI永远不会被更新。我在我的所有属性上使用INotifyPropertyChanged,并且我收集了CollectionChanged的集合,但仍然没有去。 ObservableCollection的CollectionChanged事件从未受到其中一个元素的更新的打击。



这是我原来有的代码:

  void Elements_CollectionChanged(
object sender,
System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{this.NotifyChange(Elements );

这是绑定:

 <! - 工作区 - > 
< ScrollViewer Grid.Column =1VerticalScrollBarVisibility =AutoHorizo​​ntalScrollBarVisibility =AutoMargin =5DataContext ={Binding Project}>
< Canvas x:Name =CanvasBackground =LightGrayWidth ={Binding Path = CanvasWidth}Height ={Binding Path = CanvasHeight}>
< ItemsControl ItemsSource ={Binding Path = Layers,Mode = OneWay,UpdateSourceTrigger = PropertyChanged}>
< ItemsControl.ItemsPanel>
< ItemsPanelTemplate>
< Canvas />
< / ItemsPanelTemplate>
< /ItemsControl.ItemsPanel>
< ItemsControl.ItemTemplate>

< DataTemplate>
< ItemsControl ItemsSource ={Binding Path = Elements,Mode = OneWay}>
< ItemsControl.ItemsPanel>
< ItemsPanelTemplate>
< Canvas Background ={Binding Path = BackgroundColor}
Visibility ={Binding Path = Visible,Converter = {StaticResource BoolConverter}}
Opacity ={Binding Path = Opacity
Width ={Binding ElementName = Canvas,Path = DataContext.CanvasWidth}
Height ={Binding ElementName = Canvas,Path = DataContext.CanvasHeight}>
< / Canvas>
< / ItemsPanelTemplate>
< /ItemsControl.ItemsPanel>
< ItemsControl.ItemTemplate>
< DataTemplate>
< Canvas>
< ContentControl Content ={Binding Converter = {StaticResource ElementConverter}}
Canvas.Top ={Binding Path = Top,Mode = TwoWay}
Canvas.Left ={ Binding Path = Left,Mode = TwoWay
Opacity ={Binding Path = Opacity}
MouseLeftButtonDown =ContentControl_MouseLeftButtonDown>
< interactiveivity:Interaction.Behaviors>
<行为:DragInCanvasBehavior />
< / interactivity:Interaction.Behaviors>
< / ContentControl>
< / Canvas>
< / DataTemplate>
< /ItemsControl.ItemTemplate>
< / ItemsControl>
< / DataTemplate>

< /ItemsControl.ItemTemplate>
< / ItemsControl>
< / Canvas>
< / ScrollViewer>

这是我的转换器:

  public class LayerElementToFrameworkElementConverter:IValueConverter 
{
public object Convert(object value,Type targetType,object parameter,System.Globalization.CultureInfo culture)
{
元素元素=值作为元素;
if(element is ImageEditor.Client.BLL.TextElement)
{
ImageEditor.Client.BLL.TextElement txt = element as ImageEditor.Client.BLL.TextElement;
返回CreateTextBlock(txt);
}
else if(element is ImageElement)
{
ImageElement imgEle = element as ImageElement;
返回CreateImage(imgEle);
}
else
返回null;
}

public object ConvertBack(object value,Type targetType,object parameter,System.Globalization.CultureInfo culture)
{
FrameworkElement frameworkElement = Value as FrameworkElement;
if(frameworkElement is TextBlock)
{
TextBlock txtBlock = value as TextBlock;
return CreateTextElement(txtBlock);
}
else if(frameworkElement为Image)
{
图像img = value as Image;
return CreateImageElement(img);
}
else
返回null;
}

private TextBlock CreateTextBlock(TextElement textElement)
{
TextBlock text = new TextBlock();
text.Text = textElement.Text;
text.Cursor = Cursors.Hand;
text.SetValue(Canvas.ZIndexProperty,textElement.Order);

ColorHexToBrushConverter converter = new ColorHexToBrushConverter();
SolidColorBrush画笔=(SolidColorBrush)converter.Convert(textElement.Color,null,null,null);
text.Foreground = brush;

返回文字;
}

private TextElement CreateTextElement(TextBlock textBlock)
{
TextElement textElement = new TextElement();
textElement.Text = textBlock.Text;
textElement.Top =(double)textBlock.GetValue(Canvas.TopProperty);
textElement.Left =(double)textBlock.GetValue(Canvas.LeftProperty);
textElement.Order =(int)textBlock.GetValue(Canvas.ZIndexProperty);

ColorHexToBrushConverter converter = new ColorHexToBrushConverter();
textElement.Color =(string)converter.ConvertBack(textBlock.Foreground,null,null,null);

return textElement;
}

private Image CreateImage(ImageElement imageElement)
{
Image img = new Image();
img.Width = imageElement.Width;
img.Height = imageElement.Height;
img.Source = imageElement.Source;
img.Opacity = imageElement.Opacity;
img.Cursor = Cursors.Hand;

img.SetValue(Canvas.ZIndexProperty,imageElement.Order);
img.SetValue(Canvas.TopProperty,imageElement.Top);
img.SetValue(Canvas.LeftProperty,imageElement.Left);

return img;
}

private ImageElement CreateImageElement(Image image)
{
ImageElement imageElement = new ImageElement();
imageElement.Width = image.Width;
imageElement.Height = image.Height;
imageElement.Source =(BitmapImage)image.Source;
imageElement.Order =(int)image.GetValue(Canvas.ZIndexProperty);

return imageElement;
}
}

这是包含收藏的类: p>

  public class Layer:BaseBLL 
{
private int numberOfElements;

#region属性
public int Order
{
get {return this.GetValue< int>(Order); }
set {this.SetValue< int>(Order,value); }
}

public string BackgroundColor
{
get {return this.GetValue< string>(BackgroundColor); }
set {this.SetValue< string>(BackgroundColor,value); }
}

public double Opacity
{
get {return this.GetValue< double>(Opacity); }
set {this.SetValue< double>(Opacity,value); }
}

public bool可见
{
get {return this.GetValue< bool>(Visible); }
set {this.SetValue< bool>(Visible,value); }
}

public ObservableCollection< Element>元素{get;组; }

public Element SelectedElement
{
get {return this.GetValue< Element>(SelectedElement); }
set {this.SetValue< Element>(SelectedElement,value);
}
#endregion

#region命令
public ICommand AddTextElementCommand {get;组; }
public ICommand AddImageElementCommand {get;组; }
public ICommand DeleteElementCommand {get;组; }
public ICommand SetSelectedElementCommand {get;组;
#endregion

#region方法
public Layer()
:this(Untitled,0,#ffffff,1,true,new ObservableCollection< ;元素>())
{
}

public Layer(string name,int order,string backgroundColor,double opacity,bool visible,ObservableCollection< Element>元素)
:base(name)
{
this.Order = order;
this.BackgroundColor = backgroundColor;
this.Opacity = opacity;
this.Visible = visible;
this.Elements = elements;

this.Elements.CollectionChanged + = new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Elements_CollectionChanged);

this.AddTextElementCommand = new DelegateCommand(AddTextElement,CanAddTextElement);
this.AddImageElementCommand = new DelegateCommand(AddImageElement,CanAddImageElement);
this.DeleteElementCommand = new DelegateCommand(DeleteElement,CanDeleteElement);
}

private void Elements_CollectionChanged(object sender,System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
foreach(e.NewItems中的元素元素)
element.PropertyChanged + = new System.ComponentModel.PropertyChangedEventHandler(element_PropertyChanged);
}

void element_PropertyChanged(object sender,System.ComponentModel.PropertyChangedEventArgs e)
{
this.NotifyChange(Elements);
}

private bool CanAddTextElement(object param){return true;
private void AddTextElement(object param)
{
TextElement text = new TextElement();
text.Order = this.numberOfElements;
this.Elements.Add(text);

numberOfElements ++;
this.SelectedElement = text;
}

private bool CanAddImageElement(object param){return true;
private void AddImageElement(object param)
{
var dialog = new OpenFileDialog()
{
Filter =图像文件(* .bmp; *。 ; *。gif; *。png;)| * .bmp; *。jpg; *。gif; *。png;,
Multiselect = false
};

bool? userClickedOK = dialog.ShowDialog();
if(userClickedOK == true)
{
string fileName = dialog.File.Name;
FileStream stream = dialog.File.OpenRead();

var imageSource = new BitmapImage();
使用(FileStream fileStream = stream)
{
imageSource.SetSource(fileStream);
byte [] data = new byte [fileStream.Length];
fileStream.Read(data,0,data.Length);
fileStream.Flush();
fileStream.Close();
}

ImageElement img = new ImageElement();
img.Name = fileName;
img.Order = this.numberOfElements;
img.Source = imageSource;
img.Height = imageSource.PixelHeight;
img.Width = imageSource.PixelWidth;
this.Elements.Add(img);

this.numberOfElements ++;
this.SelectedElement = img;
}
}

private bool CanDeleteElement(object param)
{
if(this.SelectedElement!= null)
return true;
else
返回false;
}

private void DeleteElement(object param)
{
throw new NotImplementedException();
}
#endregion
}

这是代码元素之一:

  public class TextElement:Element 
{
public string Text
{
get {return this.GetValue< string>(Text); }
set {this.SetValue< string>(Text,value); }
}

public int FontSize
{
get {return this.GetValue< int>(FontSize); }
set {this.SetValue< int>(FontSize,value); }
}

public bool Bold
{
get {return this.GetValue< bool>(Bold); }
set {this.SetValue< bool>(Bold,value);
}

public bool Italic
{
get {return this.GetValue< bool>(Italic); }
set {this.SetValue< bool>(Italic,value); }
}

public string Color
{
get {return this.GetValue< string>(Color); }
set {this.SetValue< string>(Color,value);
}

public FontFamily Font
{
get {return this.GetValue< FontFamily>(Font); }
set {this.SetValue< FontFamily>(Font,value);
}

public TextElement()
:this(Untitled,1,5,5,10,0,0,New text,12,false, false,#aaaaaa,新的FontFamily(Arial)
{
}

public TextElement(string name,double opacity,double top,double left,double rotateAngle ,double centerX,double centerY,
string text,int fontSize,bool bold,bool italic,string color,FontFamily font)
:base(name,opacity,top,left,rotateAngle,centerX,centerY)
{
this.Text = text;
this.FontSize = fontSize;
this.Bold = bold;
this.Italic = italic;
this.Color = color;
this.Font = font;
}
}

如果有人可以帮助我会非常感激。 / p>

解决方案

您是否从SetValue内部触发PropertyChanged事件?
否则,您应该为Element的每个属性执行。

  public string Text 
{
get {return this.GetValue< string>(Text); }
set {this.SetValue< string>(Text,value); this.InvokePropertyChanged(Text);
}

private void InvokePropertyChanged(string propertyName)
{
if(this.PropertyChanged!= null)
this.PropertyChanged(this,new PropertyChangedEventArgs(propertyName));
}


Hopefully someone can help me out with this. I am creating a Silverlight app which is used for editing images. A user has a project which contain layers which contain elements. (Elements are text and image elements).

I have a class which represents the project. It contains an ObservableCollection and each Layer has an ObservableCollection. Element is an abstract class. There is a TextElement and ImageElement class which inherit from Element.

My problem is the UI never gets updated when I change an element inside the collection. I am using INotifyPropertyChanged on all my properties and I am catching CollectionChanged on the collections but still no go. The CollectionChanged event for ObservableCollection never gets hit on an update of one of its elements.

This is the code I had originally had:

void Elements_CollectionChanged(
    object sender,     
    System.Collections.Specialized.NotifyCollectionChangedEventArgs e) 
{ this.NotifyChange("Elements"); }

This is the binding:

<!-- Workspace -->
        <ScrollViewer Grid.Column="1" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" Margin="5" DataContext="{Binding Project}">
            <Canvas x:Name="Canvas" Background="LightGray" Width="{Binding Path=CanvasWidth}" Height="{Binding Path=CanvasHeight}">
                <ItemsControl ItemsSource="{Binding Path=Layers, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}">
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <Canvas />
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                    <ItemsControl.ItemTemplate>

                        <DataTemplate>                                
                            <ItemsControl ItemsSource="{Binding Path=Elements, Mode=OneWay}">
                                <ItemsControl.ItemsPanel>
                                    <ItemsPanelTemplate>
                                        <Canvas Background="{Binding Path=BackgroundColor}"
                                                Visibility="{Binding Path=Visible, Converter={StaticResource BoolConverter}}"
                                                Opacity="{Binding Path=Opacity}"
                                                Width="{Binding ElementName=Canvas, Path=DataContext.CanvasWidth}" 
                                                Height="{Binding ElementName=Canvas, Path=DataContext.CanvasHeight}">
                                        </Canvas>
                                    </ItemsPanelTemplate>
                                </ItemsControl.ItemsPanel>
                                <ItemsControl.ItemTemplate>
                                    <DataTemplate>
                                        <Canvas>
                                            <ContentControl Content="{Binding Converter={StaticResource ElementConverter}}"
                                                            Canvas.Top="{Binding Path=Top, Mode=TwoWay}"
                                                            Canvas.Left="{Binding Path=Left, Mode=TwoWay}"
                                                            Opacity="{Binding Path=Opacity}"
                                                            MouseLeftButtonDown="ContentControl_MouseLeftButtonDown">
                                                <interactivity:Interaction.Behaviors>
                                                    <behaviors:DragInCanvasBehavior />
                                                </interactivity:Interaction.Behaviors>
                                            </ContentControl>
                                        </Canvas>
                                    </DataTemplate>
                                </ItemsControl.ItemTemplate>
                            </ItemsControl>                                
                        </DataTemplate>

                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </Canvas>
        </ScrollViewer>

This is my converter:

public class LayerElementToFrameworkElementConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        Element element = value as Element;
        if (element is ImageEditor.Client.BLL.TextElement)
        {
            ImageEditor.Client.BLL.TextElement txt = element as ImageEditor.Client.BLL.TextElement;
            return CreateTextBlock(txt);
        }
        else if (element is ImageElement)
        {
            ImageElement imgEle = element as ImageElement;
            return CreateImage(imgEle);
        }
        else
            return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        FrameworkElement frameworkElement = value as FrameworkElement;
        if (frameworkElement is TextBlock)
        {
            TextBlock txtBlock = value as TextBlock;
            return CreateTextElement(txtBlock);
        }
        else if (frameworkElement is Image)
        {
            Image img = value as Image;
            return CreateImageElement(img);
        }
        else
            return null;
    }

    private TextBlock CreateTextBlock(TextElement textElement)
    {
        TextBlock text = new TextBlock();
        text.Text = textElement.Text;
        text.Cursor = Cursors.Hand;
        text.SetValue(Canvas.ZIndexProperty, textElement.Order);

        ColorHexToBrushConverter converter = new ColorHexToBrushConverter();
        SolidColorBrush brush = (SolidColorBrush)converter.Convert(textElement.Color, null, null, null);
        text.Foreground = brush;

        return text;
    }

    private TextElement CreateTextElement(TextBlock textBlock)
    {
        TextElement textElement = new TextElement();
        textElement.Text = textBlock.Text;
        textElement.Top = (double)textBlock.GetValue(Canvas.TopProperty);
        textElement.Left = (double)textBlock.GetValue(Canvas.LeftProperty);
        textElement.Order = (int)textBlock.GetValue(Canvas.ZIndexProperty);

        ColorHexToBrushConverter converter = new ColorHexToBrushConverter();
        textElement.Color = (string)converter.ConvertBack(textBlock.Foreground, null, null, null);

        return textElement;
    }

    private Image CreateImage(ImageElement imageElement)
    {
        Image img = new Image();
        img.Width = imageElement.Width;
        img.Height = imageElement.Height;
        img.Source = imageElement.Source;
        img.Opacity = imageElement.Opacity;
        img.Cursor = Cursors.Hand;

        img.SetValue(Canvas.ZIndexProperty, imageElement.Order);
        img.SetValue(Canvas.TopProperty, imageElement.Top);
        img.SetValue(Canvas.LeftProperty, imageElement.Left);

        return img;
    }

    private ImageElement CreateImageElement(Image image)
    {
        ImageElement imageElement = new ImageElement();
        imageElement.Width = image.Width;
        imageElement.Height = image.Height;
        imageElement.Source = (BitmapImage)image.Source;
        imageElement.Order = (int)image.GetValue(Canvas.ZIndexProperty);

        return imageElement;
    }
}

This is the class which contains to collection:

public class Layer : BaseBLL
{
    private int numberOfElements;

    #region Properties
    public int Order
    {
        get { return this.GetValue<int>("Order"); }
        set { this.SetValue<int>("Order", value); }
    }

    public string BackgroundColor
    {
        get { return this.GetValue<string>("BackgroundColor"); }
        set { this.SetValue<string>("BackgroundColor", value); }
    }

    public double Opacity
    {
        get { return this.GetValue<double>("Opacity"); }
        set { this.SetValue<double>("Opacity", value); }
    }

    public bool Visible
    {
        get { return this.GetValue<bool>("Visible"); }
        set { this.SetValue<bool>("Visible", value); }
    }

    public ObservableCollection<Element> Elements { get; set; }

    public Element SelectedElement
    {
        get { return this.GetValue<Element>("SelectedElement"); }
        set { this.SetValue<Element>("SelectedElement", value); }
    }
    #endregion

    #region Commands
    public ICommand AddTextElementCommand { get; set; }
    public ICommand AddImageElementCommand { get; set; }
    public ICommand DeleteElementCommand { get; set; }
    public ICommand SetSelectedElementCommand { get; set; }
    #endregion

    #region Methods
    public Layer()
        :this("Untitled", 0, "#ffffff", 1, true, new ObservableCollection<Element>())
    {
    } 

    public Layer(string name, int order, string backgroundColor, double opacity, bool visible, ObservableCollection<Element> elements)
        : base(name)
    {
        this.Order = order;
        this.BackgroundColor = backgroundColor;
        this.Opacity = opacity;
        this.Visible = visible;
        this.Elements = elements;

        this.Elements.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Elements_CollectionChanged);

        this.AddTextElementCommand = new DelegateCommand(AddTextElement, CanAddTextElement);
        this.AddImageElementCommand = new DelegateCommand(AddImageElement, CanAddImageElement);
        this.DeleteElementCommand = new DelegateCommand(DeleteElement, CanDeleteElement);
    }

    private void Elements_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        foreach (Element element in e.NewItems)
            element.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(element_PropertyChanged);
    }

    void element_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        this.NotifyChange("Elements");
    }

    private bool CanAddTextElement(object param) { return true; }
    private void AddTextElement(object param)
    {
        TextElement text = new TextElement();
        text.Order = this.numberOfElements;
        this.Elements.Add(text);

        numberOfElements++;
        this.SelectedElement = text;
    }       

    private bool CanAddImageElement(object param) { return true; }
    private void AddImageElement(object param)
    {
        var dialog = new OpenFileDialog()
        {
            Filter = "Image Files (*.bmp;*.jpg;*.gif;*.png;)|*.bmp;*.jpg;*.gif;*.png;",
            Multiselect = false
        };

        bool? userClickedOK = dialog.ShowDialog();
        if (userClickedOK == true)
        {
            string fileName = dialog.File.Name;
            FileStream stream = dialog.File.OpenRead();

            var imageSource = new BitmapImage();
            using (FileStream fileStream = stream)
            {
                imageSource.SetSource(fileStream);
                byte[] data = new byte[fileStream.Length];
                fileStream.Read(data, 0, data.Length);
                fileStream.Flush();
                fileStream.Close();
            }

            ImageElement img = new ImageElement();
            img.Name = fileName;
            img.Order = this.numberOfElements;
            img.Source = imageSource;
            img.Height = imageSource.PixelHeight;
            img.Width = imageSource.PixelWidth;
            this.Elements.Add(img);

            this.numberOfElements++;
            this.SelectedElement = img;
        }
    }

    private bool CanDeleteElement(object param)
    {
        if (this.SelectedElement != null)
            return true;
        else
            return false;
    }

    private void DeleteElement(object param)
    {
        throw new NotImplementedException();
    }      
    #endregion
}

This is the code for the one of the Elements:

public class TextElement : Element
{
    public string Text
    {
        get { return this.GetValue<string>("Text"); }
        set { this.SetValue<string>("Text", value); }
    }

    public int FontSize
    {
        get { return this.GetValue<int>("FontSize"); }
        set { this.SetValue<int>("FontSize", value); }
    }

    public bool Bold
    {
        get { return this.GetValue<bool>("Bold"); }
        set { this.SetValue<bool>("Bold", value); }
    }

    public bool Italic
    {
        get { return this.GetValue<bool>("Italic"); }
        set { this.SetValue<bool>("Italic", value); }
    }

    public string Color
    {
        get { return this.GetValue<string>("Color"); }
        set { this.SetValue<string>("Color", value); }
    }

    public FontFamily Font
    {
        get { return this.GetValue<FontFamily>("Font"); }
        set { this.SetValue<FontFamily>("Font", value); }
    }

    public TextElement()
        : this("Untitled", 1, 5, 5, 0, 0, 0, "New text", 12, false, false, "#aaaaaa", new FontFamily("Arial"))
    {
    }

    public TextElement(string name, double opacity, double top, double left, double rotateAngle, double centerX, double centerY, 
        string text, int fontSize, bool bold, bool italic, string color, FontFamily font)
        : base(name, opacity, top, left, rotateAngle, centerX, centerY)
    {
        this.Text = text;
        this.FontSize = fontSize;
        this.Bold = bold;
        this.Italic = italic;
        this.Color = color;
        this.Font = font;
    }
}

If anyone can help I would be very grateful.

解决方案

Do you fire the PropertyChanged event from inside SetValue? Otherwise, you should do it for each property of Element.

public string Text
    {
        get { return this.GetValue<string>("Text"); }
        set { this.SetValue<string>("Text", value); this.InvokePropertyChanged("Text"); }
    }

private void InvokePropertyChanged( string propertyName )
{
  if( this.PropertyChanged != null )
    this.PropertyChanged( this, new PropertyChangedEventArgs( propertyName ) );
}

这篇关于更新ObservableCollecttion对象属性已更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆