【问题标题】:refreshing Value Converter on INotifyPropertyChanged在 INotifyPropertyChanged 上刷新值转换器
【发布时间】:2013-04-07 22:26:16
【问题描述】:

我知道这里有一些类似的话题,但我无法从他们那里得到任何答案。 我必须在我的 Windows Phone 7 应用程序中将网格的背景更新为图像或颜色。我使用我的值转换器执行此操作,它工作正常,但我必须重新加载集合,以便它更新颜色或图像。

<Grid Background="{Binding Converter={StaticResource ImageConverter}}" Width="125" Height="125" Margin="6">

转换器接收对象然后从中获取颜色和图像,这里是转换器

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {

            People myC = value as People;

            string myImage = myC.Image;
            object result = myC.TileColor;

            if (myImage != null)
            {

                BitmapImage bi = new BitmapImage();
                bi.CreateOptions = BitmapCreateOptions.BackgroundCreation;
                ImageBrush imageBrush = new ImageBrush();

                using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
                {
                    if (myIsolatedStorage.FileExists(myImage))
                    {

                        using (
                            IsolatedStorageFileStream fileStream = myIsolatedStorage.OpenFile(myImage, FileMode.Open,
                                                                                              FileAccess.Read))
                        {
                            bi.SetSource(fileStream);
                            imageBrush.ImageSource = bi;
                        }
                    }
                    else
                    {
                        return result;
                    }
                }

                return imageBrush;
            }
            else
            {
                return result;
            }

    }

我需要以某种方式更新/刷新网格标签或值转换器,以便它可以显示最新的更改!

编辑

添加了更多代码

型号:

  [Table]
    public class People : INotifyPropertyChanged, INotifyPropertyChanging
    {


        private int _peopleId;

        [Column(IsPrimaryKey = true, IsDbGenerated = true, DbType = "INT NOT NULL Identity", CanBeNull = false, AutoSync = AutoSync.OnInsert)]
        public int PeopleId
        {
            get { return _peopleId; }
            set
            {
                if (_peopleId != value)
                {
                    NotifyPropertyChanging("PeopleId");
                    _peopleId = value;
                    NotifyPropertyChanged("PeopleId");
                }
            }
        }

        private string _peopleName;

        [Column]
        public string PeopleName
        {
            get { return _peopleName; }
            set
            {
                if (_peopleName != value)
                {
                    NotifyPropertyChanging("PeopleName");
                    _peopleName = value;
                    NotifyPropertyChanged("PeopleName");
                }
            }
        }




        private string _tileColor;

        [Column]
        public string TileColor
        {
            get { return _tileColor; }
            set
            {
                if (_tileColor != value)
                {
                    NotifyPropertyChanging("TileColor");
                    _tileColor = value;
                    NotifyPropertyChanged("TileColor");
                }
            }
        }



        private string _image;

        [Column]
        public string Image
        {
            get { return _image; }
            set
            {
                if (_image != value)
                {
                    NotifyPropertyChanging("Image");
                    _image = value;
                    NotifyPropertyChanged("Image");
                }
            }
        }


        [Column]
        internal int _groupId;

        private EntityRef<Groups> _group;

        [Association(Storage = "_group", ThisKey = "_groupId", OtherKey = "Id", IsForeignKey = true)]
        public Groups Group
        {
            get { return _group.Entity; }
            set
            {
                NotifyPropertyChanging("Group");
                _group.Entity = value;

                if (value != null)
                {
                    _groupId = value.Id;
                }

                NotifyPropertyChanging("Group");
            }
        }


        [Column(IsVersion = true)]
        private Binary _version;

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

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

        #endregion

        #region INotifyPropertyChanging Members

        public event PropertyChangingEventHandler PropertyChanging;

        private void NotifyPropertyChanging(string propertyName)
        {
            if (PropertyChanging != null)
            {
                PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
            }
        }

        #endregion
    }

视图模型:

public class PeopleViewModel : INotifyPropertyChanged
{

    private PeopleDataContext PeopleDB;

    // Class constructor, create the data context object.
    public PeopleViewModel(string PeopleDBConnectionString)
    {
        PeopleDB = new PeopleDataContext(PeopleDBConnectionString);
    }


    private ObservableCollection<People> _allPeople;

    public ObservableCollection<People> AllPeople
    {
        get { return _allPeople; }
        set
        {
            _allPeople = value;
            NotifyPropertyChanged("AllPeople");
        }
    }

    public ObservableCollection<People> LoadPeople(int gid)
    {
        var PeopleInDB = from People in PeopleDB.People
                           where People._groupId == gid
                           select People;


        AllPeople = new ObservableCollection<People>(PeopleInDB);

        return AllPeople;
    }


    public void updatePeople(int cid, string cname, string image, string tilecol)
    {
        People getc = PeopleDB.People.Single(c => c.PeopleId == cid);
        getc.PeopleName = cname;
        getc.Image = image;
        getc.TileColor = tilecol;

        PeopleDB.SubmitChanges();

    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    public void NotifyPropertyChanged(string propertyName)
    {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                }
    }

    #endregion
}

申请页面

    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">

        <ListBox Margin="0,8,0,0"  x:Name="Peoplelist" HorizontalAlignment="Center"  BorderThickness="4" ItemsSource="{Binding AllPeople}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid Background="{Binding Converter={StaticResource ImageConverter}}" Width="125" Height="125" Margin="6">
                        <TextBlock Name="name" Text="{Binding PeopleName}" VerticalAlignment="Center" HorizontalAlignment="Center" TextAlignment="Center" TextWrapping="Wrap"/>
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
            <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <toolkit:WrapPanel/>
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>
        </ListBox>

    </Grid>

后面的应用程序页面代码

public partial class PeopleList : PhoneApplicationPage
{

    private int gid;
    private bool firstRun;

    public PeopleList()
    {
        InitializeComponent();
        firstRun = true;
        this.DataContext = App.ViewModel;
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {

        gid = int.Parse(NavigationContext.QueryString["Id"]);

        if (firstRun)
        {
            App.ViewModel.LoadPeople(gid);
            firstRun = false;
        }


    }

 }

【问题讨论】:

    标签: c# windows-phone-7 ivalueconverter


    【解决方案1】:

    Background="{Binding Converter={StaticResource ImageConverter}}" 建议你直接绑定到People item (这是你刷新时的问题)。

    所以,你应该重新安排一下。将 a property 改为其他一些“更高”的数据上下文。


    如何重新排列:

    1) 您的“模型”(来自数据库的实体)应该与您的视图模型不同。为了避免深入细节,它解决了很多问题 - 例如。就像你一样。 People getter/setter 通常不会以这种方式覆盖(EF 经常使用反射来处理实体等)。
    因此,制作 PeopleVM(针对单个人或 PersonViewModel) - 将内容复制到其中 - 并在其中制作 INotify - 将 People 保留为带有自动获取/设置的纯实体/poco。

    2) 与 PeopleViewModel 相同 - 它与 Db 绑定太紧密(这些也是设计指南)。
    您不应该重复使用 DbContext - 不要保存它——它是一个“一次性”对象(并缓存在里面)——所以使用using() 来处理和按需加载/更新。

    3) 用 PersonViewModel 替换主 VM 中的人员。当您从 db 加载时,首先将泵送入 PersonVM - 当您以另一种方式保存时。这对于 MVVM 来说是一个棘手的问题,您经常需要复制/复制 - 您可以使用一些工具来自动化或制作复制 ctor-s 或其他东西。
    你的ObservableCollection&lt;People&gt; AllPeople 变成ObservableCollection&lt;PersonViewModel&gt; AllPeople

    4) XAML - 您的绑定 AllPeople、PeopleName 是相同的 - 但现在指向视图模型(以及名称到 VM 名称)。
    但是您应该将grid 绑定到PersonViewModel(老人)以外的其他东西 - 因为在集合中很难“刷新”。
    a) 创建一个新的单个属性,例如 ImageAndTileColor - 并确保它在两个属性中的任何一个发生更改时更新/通知。
    b)另一种选择是使用MultiBinding - 并绑定2、3个属性 - 一个是整个PersonViewModel,就像你拥有的那样,加上其他两个属性 - 例如......

    <Grid ...>
        <Grid.Background>
            <MultiBinding Converter="{StaticResource ImageConverter}" Mode="OneWay">
                <MultiBinding.Bindings>
                    <Binding Path="Image" />
                    <Binding Path="TileColor" />
                    <Binding Path="" />
                </MultiBinding.Bindings>
            </MultiBinding>
        </Grid.Background>
        <TextBlock Name="name" Text="{Binding PeopleName}" ... />
    </Grid>
    

    这样,当 3 个更改中的任何一个发生更改时,您将强制刷新绑定 - 您仍然拥有完整的人员(实际上您可以只使用两个,因为您只需要 Image 和 TileColor) .

    5) 将您的转换器更改为 IMultiValue... 并读取发送的多个值。

    就是这样:)

    简短版:
    那是 proper way 并且肯定可以工作(这取决于您更新 Person 属性的方式/时间等) - 但您可以先尝试 short version - 只需在 People 模型上执行 multi-binding 部分 - 并希望它会工作的。如果不是,您必须执行上述所有操作。

    Windows Phone 7:
    由于没有MultiBinding...
    - 使用the workaround - 应该很相似,
    - 或者使用上面的(a) - 将网格绑定到{Binding ImageAndTileColor, Converter...}。创建新属性(如果您希望在实体/模型中执行相同操作 - 只需将其标记为 [NotMapped()]),这将是一个“复合”属性。


    http://www.thejoyofcode.com/MultiBinding_for_Silverlight_3.aspx

    【讨论】:

    • 一个集合,我在 list.ItemsSource = App.ViewModel.AllPeople; 后面的代码中将它设置为我的列表框 itemsource;一切正常,但网格背景没有改变(文本和不使用值转换器的其他内容会立即更新)
    • 感谢您的回复,请问您刷新我的收藏是什么意思?我将数据加载到页面构造函数中的可观察集合中,但之后我只是从缓存中调用已加载的集合。
    • 我可以编辑它,它无需从数据库中重新加载数据就可以工作(INotify 到目前为止工作正常)但是如果我更改任何图片,这意味着它需要值转换器来检查图片是否或背景已更改,则除非我从数据库重新加载集合,否则它不会显示更新的背景。现在我想知道我是否应该在每次更新它时从数据库中加载集合,或者这会使 INotifypropertychanged 的​​目的无效!?
    • 当然,我会尽快发布。谢谢
    • 非常感谢,Windows Phone 7 支持多重绑定吗?我无法实现 IMultiValueConverter !
    【解决方案2】:

    我明白了(感谢 NSGaga)。我将他的帖子设置为答案,以下是我所做的

    首先我需要让转换器接收 PeopleId 而不是对象本身

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
    
            int cid = (int)value;
            People myC = App.ViewModel.getPerson(cid);
    
                string myImage = myC.Image;
                object result = myC.TileColor;
    
                if (myImage != null)
                {
    
                    BitmapImage bi = new BitmapImage();
                    bi.CreateOptions = BitmapCreateOptions.BackgroundCreation;
                    ImageBrush imageBrush = new ImageBrush();
    
                    using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
                    {
                        if (myIsolatedStorage.FileExists(myImage))
                        {
    
                            using (
                                IsolatedStorageFileStream fileStream = myIsolatedStorage.OpenFile(myImage, FileMode.Open,
                                                                                                  FileAccess.Read))
                            {
                                bi.SetSource(fileStream);
                                imageBrush.ImageSource = bi;
                            }
                        }
                        else
                        {
                            return result;
                        }
                    }
    
                    return imageBrush;
                }
                else
                {
                    return result;
                }
    
        }
    

    然后,每当我像这样更新 Image 或 TileColor 时,我只需添加调用 NotifyPropertyChanged("PeopleId")

        private string _tileColor;
    
        [Column]
        public string TileColor
        {
            get { return _tileColor; }
            set
            {
                if (_tileColor != value)
                {
                    NotifyPropertyChanging("TileColor");
                    _tileColor = value;
                    NotifyPropertyChanged("TileColor");
                    NotifyPropertyChanged("PeopleId");
                }
            }
        }
    
    
    
        private string _image;
    
        [Column]
        public string Image
        {
            get { return _image; }
            set
            {
                if (_image != value)
                {
                    NotifyPropertyChanging("Image");
                    _image = value;
                    NotifyPropertyChanged("Image");
                    NotifyPropertyChanged("PeopleId");
                }
            }
        }
    

    这会强制值转换器刷新:)

    【讨论】:

      猜你喜欢
      • 2011-06-18
      • 1970-01-01
      • 1970-01-01
      • 2014-02-01
      • 2013-06-18
      • 2015-05-01
      • 2013-05-20
      • 1970-01-01
      • 2020-06-20
      相关资源
      最近更新 更多