Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/131.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Xamarin.forms 尝试将值转换器与OnBindingContextChanged的ListView(循环缓存策略)一起使用_Xamarin.forms - Fatal编程技术网

Xamarin.forms 尝试将值转换器与OnBindingContextChanged的ListView(循环缓存策略)一起使用

Xamarin.forms 尝试将值转换器与OnBindingContextChanged的ListView(循环缓存策略)一起使用,xamarin.forms,Xamarin.forms,不确定我的问题格式是否恰当,如果没有,请告诉我。但我试图简单地将背景颜色绑定到viewcell中的值。事实上,我有这个工作。问题是当我更新一个值时,我看不到背景颜色的变化。实现有点复杂,但下面是我的代码 ViewCell(OnBindingContextChanged) 所以本质上我只是建立我的布局。我决定只发布在我的OnBindingContextChanged方法中设置绑定的相关代码。如果有人需要任何其他代码,我很乐意添加它,只是不知道它是否相关。我的ViewCell类是一个简单的类,它只继

不确定我的问题格式是否恰当,如果没有,请告诉我。但我试图简单地将背景颜色绑定到viewcell中的值。事实上,我有这个工作。问题是当我更新一个值时,我看不到背景颜色的变化。实现有点复杂,但下面是我的代码

ViewCell(OnBindingContextChanged)

所以本质上我只是建立我的布局。我决定只发布在我的
OnBindingContextChanged
方法中设置绑定的相关代码。如果有人需要任何其他代码,我很乐意添加它,只是不知道它是否相关。我的ViewCell类是一个简单的类,它只继承了
ViewCell

这是我的转换器:

public class GridCellBackgroundColorConverter : Xamarin.Forms.IValueConverter
{
    #region IValueConverter Members

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

            var cell = (XamarinMobile.ViewModels.GridCellViewModel)value;

            if(cell.HasRead)
            {
                //return with shadow
                return Xamarin.Forms.Color.FromRgba(0,0,0,0.6);
            } else
            {
                //return no shadow
                return Xamarin.Forms.Color.FromRgba(0, 0, 0, 0.0);
            }

        } catch(System.Exception ex)
        {
            return null;
        }

    }

    public object ConvertBack(object value, Type targetType, object parameter,
        System.Globalization.CultureInfo culture)
    {
        throw new NotSupportedException();
    }

    #endregion
}
简单。它起作用了。现在是棘手的部分。我描述的网格是一个包含故事单元的列表视图。用户将单击一个图像,这将把他们带到一个故事页面。当用户在故事页面中时,他们可以返回网格转到另一个故事,或者向左或向右滑动,这样就可以转到另一个故事。当用户从我们的网格转到一个故事页面时,单元格会得到很好的更新。但是如果一个用户不是从网格中滑动到另一个故事,那就是我的问题所在。在我的故事页面中,我有一个逻辑,可以遍历网格单元格,找到你当前所在的故事(你浏览到的故事),并查看它是否在网格中,如果它在网格中,我会更新单元格的
HasRead
属性。因此:

            //find the cell in the grid (if exists)
            ViewModels.GridCellViewModel cell = App.GridCells.Where(x => x.StoryId == App.Story.StoryId).FirstOrDefault();
            if (cell != null)
            {
                cell.HasRead = true;
            }

这是可行的,但是。。。它不会触发值转换器来更改属性。我做错了什么?如何获取它,以便更新属性并使其触发值转换器

我猜您的转换器没有触发,因为您在技术上绑定了viewcell本身,而不是HasRead属性。当您设置HasRead时,它将(假设它正在实现INotifyPropertyChanged)触发一个PropertyChangedEvent,它将触发绑定并调用值转换器。但是,由于绑定指向viewcell本身,因此只有当该对象发生更改时才会触发,并且忽略该对象上其他位置的属性更改

一种可能的解决方案是将绑定更改为指向HasRead(而不是“.”),并将转换器更新为直接使用布尔值,而不是使用viewcell。这对于转换器来说是一个更好的实践

这就是说,这并没有真正遵循通常推荐用于xamarin表单应用程序的mvvm模式。我的建议是使用一个viewmodel,该viewmodel的属性可以保存您的故事模型(如果需要逻辑,可以包装在它们自己的故事视图模型中),并确保VM和模型类实现INotifyPropertyChanged。将VM作为页面的datacontext,将列表绑定到listview源,listview itemtemplate内容将绑定到每个故事。每个故事都可以有一个HasRead属性,该属性通过更新的转换器绑定到背景色

像这样:

<ContentPage
x:Class="Stack_Stories.MainPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Stack_Stories">
<ContentPage.BindingContext>
    <local:StoriesViewModel x:Name="VM" />
</ContentPage.BindingContext>
<ContentPage.Resources>
    <ResourceDictionary>
        <local:StoryReadBackgroundColorConverter x:Key="HasReadColor" />
    </ResourceDictionary>
</ContentPage.Resources>

<ListView ItemsSource="{Binding Stories}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <Grid x:Name="StoryGrid" BackgroundColor="{Binding HasRead, Converter={StaticResource HasReadColor}}">
                    <Button Command="{Binding ToggleReadCommand}" Text="{Binding Name}" />
                </Grid>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

公共类StoryViewModel:INotifyPropertyChanged
{
私有字符串_name=“”;
公共字符串名
{
获取{return\u name;}
设置{u name=value;OnPropertyChanged();}
}
private bool\u hasRead=false;
公共图书馆
{
获取{return\u hasRead;}
设置{u hasRead=value;OnPropertyChanged();}
}
专用命令_toggleRead;
公共命令切换READCOMMAND
{
得到
{
返回\u切换读取
??(_toggleRead=新命令(()=>HasRead=!HasRead));
}
}
公共事件属性更改事件处理程序属性更改;
受保护的OnPropertyChanged无效([CallerMemberName]字符串propertyName=null)
{
PropertyChanged?.Invoke(这是新的PropertyChangedEventArgs(propertyName));
}
}
公共类StoriesViewModel:INotifyPropertyChanged
{
公共故事视图模型()
{
//添加示例故事
添加(新的StoryViewModel{Name=“First Story”});
添加(新的StoryViewModel{Name=“Second Story”,HasRead=true});
}
私有ObservableCollection_stories=新ObservableCollection();
公开收集故事
{
获取{return\u stories;}
设置{u stories=value;OnPropertyChanged();}
}
公共事件属性更改事件处理程序属性更改;
受保护的OnPropertyChanged无效([CallerMemberName]字符串propertyName=null)
{
PropertyChanged?.Invoke(这是新的PropertyChangedEventArgs(propertyName));
}
}
公共类StoryReadBackgroundColorConverter:IValueConverter
{
公共对象转换(对象值、类型targetType、对象参数、CultureInfo区域性)
{
如果(!(值为bool))返回null;
返回(bool)值?Color.FromRgba(0,0,0,0.6):Color.FromRgba(0,0,0,0.0);
}
公共对象转换回(对象值、类型targetType、对象参数、CultureInfo区域性)
{
抛出新的NotImplementedException();
}
}

什么都没有?该死对如何通过onbindingcontext更改绑定viewcell一点都不了解?是的,我将它绑定到了我的viewmodel,瞧!工作得很有魅力。虽然有点混乱,因为在ViewCell中设置布局很奇怪,但是在更新视图模型时会发生变化。尽管如此,我还是采取了类似的方法,因此我标记了您的答案:)
<ContentPage
x:Class="Stack_Stories.MainPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Stack_Stories">
<ContentPage.BindingContext>
    <local:StoriesViewModel x:Name="VM" />
</ContentPage.BindingContext>
<ContentPage.Resources>
    <ResourceDictionary>
        <local:StoryReadBackgroundColorConverter x:Key="HasReadColor" />
    </ResourceDictionary>
</ContentPage.Resources>

<ListView ItemsSource="{Binding Stories}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <Grid x:Name="StoryGrid" BackgroundColor="{Binding HasRead, Converter={StaticResource HasReadColor}}">
                    <Button Command="{Binding ToggleReadCommand}" Text="{Binding Name}" />
                </Grid>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>
    public class StoryViewModel : INotifyPropertyChanged
{
    private string _name = "";
    public string Name
    {
        get { return _name; }
        set { _name = value; OnPropertyChanged(); }
    }

    private bool _hasRead = false;
    public bool HasRead
    {
        get { return _hasRead; }
        set { _hasRead = value; OnPropertyChanged(); }
    }

    private Command _toggleRead;
    public Command ToggleReadCommand    
    {
        get
        {
            return _toggleRead
                ?? (_toggleRead = new Command(() => HasRead = !HasRead));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}
public class StoriesViewModel : INotifyPropertyChanged
{
    public StoriesViewModel()
    {
        // add sample stories
        Stories.Add(new StoryViewModel { Name = "First Story" });
        Stories.Add(new StoryViewModel { Name = "Second Story", HasRead=true });
    }

    private ObservableCollection<StoryViewModel> _stories = new ObservableCollection<StoryViewModel>();
    public ObservableCollection<StoryViewModel> Stories
    {
        get { return _stories; }
        set { _stories = value; OnPropertyChanged(); }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

public class StoryReadBackgroundColorConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (!(value is bool)) return null;

        return (bool)value ? Color.FromRgba(0, 0, 0, 0.6) : Color.FromRgba(0, 0, 0, 0.0);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}