我遇到了奇怪的问题,我无法理解。在主页面中,我只有一个按钮导航到第二页并保存我的模型:
public class Model : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaiseProperty(string property) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
private int index = 0;
public int Index
{
get { Debug.WriteLine($"Getting value {index}"); return index; }
set { Debug.WriteLine($"Setting value {value}"); index = value; RaiseProperty(nameof(Index)); }
}
}
public sealed partial class MainPage : Page
{
public static Model MyModel = new Model();
public MainPage()
{
this.InitializeComponent();
SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = AppViewBackButtonVisibility.Visible;
SystemNavigationManager.GetForCurrentView().BackRequested += (s, e) => { if (Frame.CanGoBack) { e.Handled = true; Frame.GoBack(); } };
}
private void Button_Click(object sender, RoutedEventArgs e) => Frame.Navigate(typeof(BlankPage));
}
在第二页上只有 ComboBox ,它在 SelectedIndex 中有双向绑定:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ComboBox SelectedIndex="{x:Bind MyModel.Index, Mode=TwoWay}">
<x:String>First</x:String>
<x:String>Second</x:String>
<x:String>Third</x:String>
</ComboBox>
</Grid>
public sealed partial class BlankPage : Page
{
public Model MyModel => MainPage.MyModel;
public BlankPage()
{
this.InitializeComponent();
this.Unloaded += (s, e) => Debug.WriteLine("--- page unloaded ---");
DataContext = this;
}
}
没什么特别的。问题是,当我使用Binding
和x:Bind
时,我得到两个不同的输出,但最糟糕的是,在每个新导航到同一页面之后,属性的getter(以及x:Bind
中的setter)是越来越多地打电话:
旧页面仍驻留在内存中,仍然订阅了属性,这是可以理解的。如果我们从页面返回后运行GC.Collect()
,我们将从头开始。
但是如果我们使用旧的绑定与单向并选择更改事件:
<ComboBox SelectedIndex="{Binding MyModel.Index, Mode=OneWay}" SelectionChanged="ComboBox_SelectionChanged">
以及eventhandler:
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.RemovedItems.Count > 0 && e.AddedItems.FirstOrDefault() != null)
MyModel.Index = (sender as ComboBox).Items.IndexOf(e.AddedItems.FirstOrDefault());
}
然后它将“正常”工作 - 只有一个getter和setter,无论我们之前导航到页面多少次。
所以我的主要问题是:
您可以download from here的工作样本。
答案 0 :(得分:2)
实际上,当您对tokenizer
事件使用OneWay
绑定时,更改选择后只会调用SectionChanged
属性的 setter 。永远不会到达 getter 因此您没有看到多个“获取价值......”。
但为什么 getter 没有被调用?
在这一行设置一个断点 -
Index
您会看到PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
的值为PropertyChanged
。所以null
方法永远不会被触发。我怀疑这可能是Invoke
中的传统绑定设置为ComboBox
的错误。每当您更改选择时,绑定都会被破坏,因此OneWay
为PropertyChanged
。如果您更改为使用null
,则此问题就会消失。
如您所知,x:Bind
只会在需要时收集已弃用的页面实例。因此,有时您会看到GC
在多个位置被引用,无论您选择哪种绑定机制。
保证 getter 和 setter 仅被调用一次的一种方法是将第二个Index
的{{1}}更改为{{ 1}}。这样做可以确保页面的单个实例。
答案 1 :(得分:0)
即使您从新的BlankPage
导航到新的GC.Collect()
,其他页面仍然在内存中,并且仍然在静态模型中绑定为@KiranPaul评论。
现在,如果你,如你所评论的那样,改变为无静电且仍然表现相同,那是因为你犯了同样的错误。即使它不是静态的,你仍然使用MainPage中的相同变量。(我认为它不可能,因为它不是静态的)
因此,内存中没有PropertyChanged
- ed的所有页面都会引发 public sealed partial class BlankPage : Page
{
public Model MyModel = new Model() { Index = MainPage.MyModel.Index };
public BlankPage()
{
this.InitializeComponent();
this.Unloaded += (s, e) => { MainPage.MyModel.Index = MyModel.Index; Debug.WriteLine("--- page unloaded ---"); };
DataContext = this;
}
}
事件。因为MyModel总是相同的。
尝试这应该工作。每次导航到BlankPage时,都会实例化一个新模型并传递索引。然后,当您卸载页面时,您更新MainPage.Model中的值。这样,当您离开BlankPage时,您将只看到Set和Get in Output。
GC.Collect()
或者当您离开BlankPage时,您可以:
Binding
修改强>
使用GC.Collect()
如果你真的很快就会这样做。我的猜测是GC.Collect()
被称为
所以我搜索了一下,我发现了这个:
Binding vs. x:Bind, using StaticResource as a default and their differences in DataContext
答案是:
Windows 10的{x:Bind}标记扩展名 - 是{Binding}的替代品。 {x:Bind}缺少{Binding}的一些功能,但它比{Binding}在更短的时间和更少的内存中运行,并支持更好的调试。
所以Binding肯定会有所不同,它可能会调用composer.json
或Unbind it self ??。也许看看x:Bind markup
答案 2 :(得分:0)
您可以尝试将See the list()
method implementation添加到此绑定中以获得一些亮点。
另外,我建议交换这些行,使它们看起来像这样:
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
System.out.println("inside on start command for service");
myPrefs = this.getSharedPreferences("settings", this.MODE_PRIVATE);
checkTime();
return START_STICKY;
}
// to check if the time for alarm is here
private void checkTime() {
// TODO Auto-generated method stub
try{
System.out.println("inside check time");
Calendar cal;
cal = Calendar.getInstance();
if (08 == cal.get(cal.HOUR_OF_DAY) && 00 == cal.get(cal.MINUTE)) {
// to call db and check for events
nm = new MyNotificationManager(this);
if (nm.checkEvent()) {
nm.setNotifications();
}
}
}catch(Exception e){
System.out.println("inside exception for check time "+e.toString());
}
}
它可能会搞乱你的绑定。当您调用initializeComponent时,它会构建xaml树但是对于绑定我猜它使用旧的DataContext,然后您立即更改DataContext,强制重新绑定每个属性。