Xamarin Forms 设置插件可绑定
Xamarin Forms Settings Plugin Bindable
我一直是非常棒的 Xamarin 跨平台设置插件 https://components.xamarin.com/view/SettingsPlugin(确切地说是 PCL 中的 Nuget 版本)
它运行良好,但现在使用 Xamarin 表单我真的希望能够绑定到设置值。即我想在内容页面上有一个标签,上面写着:"The settings value is: [value]" 并在设置更改时更新。
设置 class 如下所示:
public static class Settings {
private static ISettings AppSettings
{
get
{
return CrossSettings.Current;
}
}
#region Setting Constants
const string HOT_TIME_COUNT_KEY = "hotTimeCount";
private static readonly int HOT_TIME_COUNT_DEFAULT = 0;
#endregion
public static int HotTimeCount
{
get { return AppSettings.GetValueOrDefault(HOT_TIME_COUNT_KEY, HOT_TIME_COUNT_DEFAULT); }
set { AppSettings.AddOrUpdateValue(HOT_TIME_COUNT_KEY, value); }
}
}
我似乎无法弄清楚完成这项工作需要什么格式? BindableProperty.Create?它需要 OnPropertyChanged 方法吗?设置 Class 是否必须派生自 BindableObject?
我创建了这个库 :) 你总是可以 post 关于 github 的问题,但本质上你需要创建一个视图模型 public 属性您希望将数据绑定到然后从那里调入设置并在值更改时发出 属性 更改通知。您的 Settings.cs 可以保持不变,但您需要创建视图模型,例如:
public class MyViewModel : INotifyPropertyChanged
{
public int Time
{
get { return Settings.HotTimeCount; }
set
{
if (Settings.HotTimeCount == value)
return;
Settings.HotTimeCount = value;
OnPropertyChanged();
}
}
private Command increase;
public Command IncreaseCommand
{
get
{
return increase ?? (increase = new Command(() =>Time++));
}
}
#region INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName]string name = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed(this, new PropertyChangedEventArgs(name));
}
#endregion
}
然后您 XAML 在您的内容页面中将如下所示:
<StackLayout Padding="25">
<Button Text="Increase" Command="{Binding IncreaseCommand}"/>
<Label Text="{Binding Time, StringFormat='The time is {0:F0}'}"/>
</StackLayout>
确保在页面的 xaml.cs 中设置 BindingContext:
public partial class MyPage : ContentPage
{
public MyPage()
{
InitializeComponent();
BindingContext = new MyViewModel();
}
}
这实际上并没有太多需要实际实现的代码,因为您的 ViewModel 将有一个实现 INotifyProprety 的 BaseViewModel 已更改,所以实际上您只是添加
public int Time
{
get { return Settings.HotTimeCount; }
set
{
if (Settings.HotTimeCount == value)
return;
Settings.HotTimeCount = value;
OnPropertyChanged();
}
}
更神奇的方式
但是,利用 C# 的强大功能并了解数据绑定的工作原理,您可以首先创建一个所有内容都将使用的 BaseViewModel:
public class BaseViewModel : INotifyPropertyChanged
{
public Settings Settings
{
get { return Settings.Current; }
}
#region INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName]string name = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed(this, new PropertyChangedEventArgs(name));
}
#endregion
}
请注意我对 Settings.Current 的引用,我们现在需要将其实现为单例,但我们将使用我们的 BaseViewModel,因此我们不必重新-实施 INotifyPropertyChanged:
public class Settings : BaseViewModel
{
static ISettings AppSettings
{
get
{
return CrossSettings.Current;
}
}
static Settings settings;
public static Settings Current
{
get { return settings ?? (settings = new Settings()); }
}
#region Setting Constants
const string HOT_TIME_COUNT_KEY = "hotTimeCount";
static readonly int HOT_TIME_COUNT_DEFAULT = 0;
#endregion
public int HotTimeCount
{
get
{
return AppSettings.GetValueOrDefault<int>(HOT_TIME_COUNT_KEY, HOT_TIME_COUNT_DEFAULT);
}
set
{
if (AppSettings.AddOrUpdateValue<int>(HOT_TIME_COUNT_KEY, value))
OnPropertyChanged();
}
}
}
当然,现在我们仍然希望创建一个唯一的 ViewModel,我们的 XAML 视图将绑定到:
public class MyViewModel : BaseViewModel
{
private Command increase;
public Command IncreaseCommand
{
get
{
return increase ?? (increase = new Command(() =>Settings.HotTimeCount++));
}
}
}
请注意,我们现在继承自 BaseViewModel,这意味着我们的命令实际上可以递增 Settings.HotTimeCount!但是现在我们必须稍微调整一下我们的 Xaml 关于我们实际为我们的标签绑定的数据:
<StackLayout Padding="25">
<Button Text="Increase" Command="{Binding IncreaseCommand}"/>
<Label BindingContext="{Binding Settings}" Text="{Binding HotTimeCount, StringFormat='The time is {0:F0}'}"/>
</StackLayout>
</ContentPage.Content>
请注意,我正在将 BindingContext 设置为我们的设置,它在我们的标签的 BaseViewModel 中,这必须完成,因为它现在所在的位置。就是这样。
我会用这些信息更新我的自述文件。
我一直是非常棒的 Xamarin 跨平台设置插件 https://components.xamarin.com/view/SettingsPlugin(确切地说是 PCL 中的 Nuget 版本)
它运行良好,但现在使用 Xamarin 表单我真的希望能够绑定到设置值。即我想在内容页面上有一个标签,上面写着:"The settings value is: [value]" 并在设置更改时更新。
设置 class 如下所示:
public static class Settings {
private static ISettings AppSettings
{
get
{
return CrossSettings.Current;
}
}
#region Setting Constants
const string HOT_TIME_COUNT_KEY = "hotTimeCount";
private static readonly int HOT_TIME_COUNT_DEFAULT = 0;
#endregion
public static int HotTimeCount
{
get { return AppSettings.GetValueOrDefault(HOT_TIME_COUNT_KEY, HOT_TIME_COUNT_DEFAULT); }
set { AppSettings.AddOrUpdateValue(HOT_TIME_COUNT_KEY, value); }
}
}
我似乎无法弄清楚完成这项工作需要什么格式? BindableProperty.Create?它需要 OnPropertyChanged 方法吗?设置 Class 是否必须派生自 BindableObject?
我创建了这个库 :) 你总是可以 post 关于 github 的问题,但本质上你需要创建一个视图模型 public 属性您希望将数据绑定到然后从那里调入设置并在值更改时发出 属性 更改通知。您的 Settings.cs 可以保持不变,但您需要创建视图模型,例如:
public class MyViewModel : INotifyPropertyChanged
{
public int Time
{
get { return Settings.HotTimeCount; }
set
{
if (Settings.HotTimeCount == value)
return;
Settings.HotTimeCount = value;
OnPropertyChanged();
}
}
private Command increase;
public Command IncreaseCommand
{
get
{
return increase ?? (increase = new Command(() =>Time++));
}
}
#region INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName]string name = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed(this, new PropertyChangedEventArgs(name));
}
#endregion
}
然后您 XAML 在您的内容页面中将如下所示:
<StackLayout Padding="25">
<Button Text="Increase" Command="{Binding IncreaseCommand}"/>
<Label Text="{Binding Time, StringFormat='The time is {0:F0}'}"/>
</StackLayout>
确保在页面的 xaml.cs 中设置 BindingContext:
public partial class MyPage : ContentPage
{
public MyPage()
{
InitializeComponent();
BindingContext = new MyViewModel();
}
}
这实际上并没有太多需要实际实现的代码,因为您的 ViewModel 将有一个实现 INotifyProprety 的 BaseViewModel 已更改,所以实际上您只是添加
public int Time
{
get { return Settings.HotTimeCount; }
set
{
if (Settings.HotTimeCount == value)
return;
Settings.HotTimeCount = value;
OnPropertyChanged();
}
}
更神奇的方式
但是,利用 C# 的强大功能并了解数据绑定的工作原理,您可以首先创建一个所有内容都将使用的 BaseViewModel:
public class BaseViewModel : INotifyPropertyChanged
{
public Settings Settings
{
get { return Settings.Current; }
}
#region INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName]string name = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed(this, new PropertyChangedEventArgs(name));
}
#endregion
}
请注意我对 Settings.Current 的引用,我们现在需要将其实现为单例,但我们将使用我们的 BaseViewModel,因此我们不必重新-实施 INotifyPropertyChanged:
public class Settings : BaseViewModel
{
static ISettings AppSettings
{
get
{
return CrossSettings.Current;
}
}
static Settings settings;
public static Settings Current
{
get { return settings ?? (settings = new Settings()); }
}
#region Setting Constants
const string HOT_TIME_COUNT_KEY = "hotTimeCount";
static readonly int HOT_TIME_COUNT_DEFAULT = 0;
#endregion
public int HotTimeCount
{
get
{
return AppSettings.GetValueOrDefault<int>(HOT_TIME_COUNT_KEY, HOT_TIME_COUNT_DEFAULT);
}
set
{
if (AppSettings.AddOrUpdateValue<int>(HOT_TIME_COUNT_KEY, value))
OnPropertyChanged();
}
}
}
当然,现在我们仍然希望创建一个唯一的 ViewModel,我们的 XAML 视图将绑定到:
public class MyViewModel : BaseViewModel
{
private Command increase;
public Command IncreaseCommand
{
get
{
return increase ?? (increase = new Command(() =>Settings.HotTimeCount++));
}
}
}
请注意,我们现在继承自 BaseViewModel,这意味着我们的命令实际上可以递增 Settings.HotTimeCount!但是现在我们必须稍微调整一下我们的 Xaml 关于我们实际为我们的标签绑定的数据:
<StackLayout Padding="25">
<Button Text="Increase" Command="{Binding IncreaseCommand}"/>
<Label BindingContext="{Binding Settings}" Text="{Binding HotTimeCount, StringFormat='The time is {0:F0}'}"/>
</StackLayout>
</ContentPage.Content>
请注意,我正在将 BindingContext 设置为我们的设置,它在我们的标签的 BaseViewModel 中,这必须完成,因为它现在所在的位置。就是这样。
我会用这些信息更新我的自述文件。