x:Bind 事件绑定的语法给出错误 CS0122:由于保护级别而无法访问
x:Bind syntax for event binding giving error CS0122: inaccessible due to protection level
我在使用新绑定模式的 Windows 10 通用应用程序中有一个基本页面。
我正在将 ViewModel 加载到 MainPage.xaml.cs 代码隐藏的 public 属性 中。这个 ViewModel 包含一堆属性,我将它们绑定到我的控件上的属性,它们工作得很好。
public sealed partial class MainPage : Page
{
public MainViewModel MainVM { get; set; }
public MainPage()
{
this.MainVM = SimpleIoc.Default.GetInstance<MainViewModel>();
this.InitializeComponent();
}
... more stuff that isn't important ...
}
现在我想绑定到 ListView 上的 SelectionChanged 事件。我在我的 ViewModel 中使用以下内容:
public void AccountsSelectionChanged(object sender, SelectionChangedEventArgs e)
{
.... stuff ....
}
这是我的 XAML:
<ListView VerticalAlignment="Bottom"
ItemsSource="{x:Bind MainVM.Accounts}"
ItemTemplate="{StaticResource AccountItemTemplate}"
SelectionMode="Single"
SelectionChanged="{x:Bind MainVM.AccountsSelectionChanged}"
Grid.Row="1">
<ListView.Header>
<TextBlock>Accounts</TextBlock>
</ListView.Header>
</ListView>
这是疯狂的事情......有一段时间,这很奏效!几个小时后,我开始收到此错误:
Error CS0122 'MainPage.MainPage_obj1_Bindings.MainPage_obj1_BindingsTracking.cache_MainVM' is inaccessible due to its protection level
很可能是我在某处进行了更改导致了这种情况,但我不知道是在哪里。如果我删除对 SelectionChanged 事件的绑定,则此错误消失。但它以前是工作的!我不知道还能做什么。我已经尝试清理解决方案并在没有绑定的情况下重建,然后将其放回原处,但它不起作用。
我已经验证每个可能涉及的 class 都是 public 并且有一个 public 构造函数。重新启动 VS2015 RC 没有帮助,重新启动也没有帮助 Windows 10(内部版本 10074)。
EDIT - 当我将处理程序直接放在 MainPage.xaml.cs 的代码隐藏中时,我已经验证事件的 x:Bind 模式确实有效XAML:
SelectionChanged="{x:Bind AccountsSelectionChanged}"
我的视图模型是 public、public、public。我不确定我错过了什么。
任何人都可以提供其他东西来尝试吗?
这是一件很奇怪的事情。我的 MainPage 上有两个 ListView。首先,我有一个 ObservableCollection of Account classes 绑定为 ItemsSource。我还将 SelectionChanged 事件绑定到同一 ViewModel 上的处理程序。这是给我带来麻烦的事件。
在另一个 ListView 上,我想显示文件夹 classes 的 ObservableCollection,selected 帐户的 属性。
<ListView VerticalAlignment="Top"
Margin="0,48,0,0"
ItemsSource="{x:Bind MainVM.SelectedAccount.Folders, Mode=OneWay}"
ItemTemplate="{StaticResource FolderItemTemplate}"
Grid.Row="0">
<ListView.Header>
<TextBlock>Folders</TextBlock>
</ListView.Header>
</ListView>
SelectedAccount 在第一个 ListView 的事件处理程序中重新设置。
我在博客上读到 x:Bind 命令似乎默认为 OneTime 绑定而不是 OneWay,所以我在 ItemsSource 上将 Mode 设置为 OneWay。此绑定将要更改,因此我认为这是一个合适的设置。
然而,这就是我所有问题的根源!我 删除了 Mode=OneWay 设置 并且我的项目编译得很好。奇怪的是,我可以保留此 Mode=OneWay 设置并 删除 另一个 ListView 中的事件绑定,它会编译。我就是不能两者兼得。
我不知道这是否会影响我对这个 ListView 的计划,但至少我现在可以编译了。
EDIT - 这只是答案的一半......我无法使用这些约束进行正确绑定。我需要弄清楚为什么会这样。
编辑 2
我的解决方法是停止使用该事件,而是绑定到 ListView 上的 SelectedItem 属性。 SelectionMode 需要设置为 Single 才能正常工作。此外,SelectedItem 输出一个对象类型,因此我需要设置一个 getter/setter,在将对象传递给私有变量时将其转换为原始帐户 class。当我删除对事件的绑定时,我可以将此 ListView 属性 设置为 Mode=TwoWay 而不会出现任何问题。
编辑 3
实际上有两种解决方法。一般来说,这个总是有效的。只需在代码隐藏中处理事件。由于您的 ViewModel 是代码隐藏上的 public 属性,因此您可以从事件处理程序调用 ViewModel 上的 public 方法并输入相同的参数(或 none ).
//codebehind
//HeadersVM is my ViewModel
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
foreach (var item in e.AddedItems)
HeadersVM.SelectedHeaders.Add((Models.MailHeader)item);
foreach (var item in e.RemovedItems)
HeadersVM.SelectedHeaders.Remove((Models.MailHeader)item);
}
private void BackButton_Click(object sender, RoutedEventArgs e)
{
this.HeadersVM.GoBack();
}
否则,对于特定于 ListView 的 SelectedItem 的解决方法,您可以双向绑定到 SelectedItem 属性。然后,创建一个转换器,其 ConvertBack 方法将对象转换为您的模型。
public class ObjectToAccountConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
if (value != null)
return (Models.Account)value;
return value;
}
}
//in App.xaml Resources
<converters:ObjectToAccountConverter x:Key="ObjectToAccountConverter "/>
//in your Page.xaml
<ListView VerticalAlignment="Top"
Margin="0,48,0,0"
ItemsSource="{x:Bind MainVM.Accounts}"
ItemTemplate="{StaticResource AccountTemplate}"
SelectedItem="{x:Bind MainVM.SelectedAccount, Mode=TwoWay, Converter={StaticResouce ObjectToAccountConverter }}"
Grid.Row="0">
<ListView.Header>
<TextBlock>Folders</TextBlock>
</ListView.Header>
</ListView>
OR 而不是创建转换器来将对象转换回您的模型,您可以将视图模型中的 属性 设为通用对象而不是您的实际对象class:
private Models.Account _selectedAccount = null;
public object SelectedAccount
{
get { return _selectedAccount; }
set
{
if (_selectedAccount != value)
{
_selectedAccount = (Models.Account)value;
RaisePropertyChanged();
RaisePropertyChanged("Folders");
}
}
}
我在使用新绑定模式的 Windows 10 通用应用程序中有一个基本页面。
我正在将 ViewModel 加载到 MainPage.xaml.cs 代码隐藏的 public 属性 中。这个 ViewModel 包含一堆属性,我将它们绑定到我的控件上的属性,它们工作得很好。
public sealed partial class MainPage : Page
{
public MainViewModel MainVM { get; set; }
public MainPage()
{
this.MainVM = SimpleIoc.Default.GetInstance<MainViewModel>();
this.InitializeComponent();
}
... more stuff that isn't important ...
}
现在我想绑定到 ListView 上的 SelectionChanged 事件。我在我的 ViewModel 中使用以下内容:
public void AccountsSelectionChanged(object sender, SelectionChangedEventArgs e)
{
.... stuff ....
}
这是我的 XAML:
<ListView VerticalAlignment="Bottom"
ItemsSource="{x:Bind MainVM.Accounts}"
ItemTemplate="{StaticResource AccountItemTemplate}"
SelectionMode="Single"
SelectionChanged="{x:Bind MainVM.AccountsSelectionChanged}"
Grid.Row="1">
<ListView.Header>
<TextBlock>Accounts</TextBlock>
</ListView.Header>
</ListView>
这是疯狂的事情......有一段时间,这很奏效!几个小时后,我开始收到此错误:
Error CS0122 'MainPage.MainPage_obj1_Bindings.MainPage_obj1_BindingsTracking.cache_MainVM' is inaccessible due to its protection level
很可能是我在某处进行了更改导致了这种情况,但我不知道是在哪里。如果我删除对 SelectionChanged 事件的绑定,则此错误消失。但它以前是工作的!我不知道还能做什么。我已经尝试清理解决方案并在没有绑定的情况下重建,然后将其放回原处,但它不起作用。
我已经验证每个可能涉及的 class 都是 public 并且有一个 public 构造函数。重新启动 VS2015 RC 没有帮助,重新启动也没有帮助 Windows 10(内部版本 10074)。
EDIT - 当我将处理程序直接放在 MainPage.xaml.cs 的代码隐藏中时,我已经验证事件的 x:Bind 模式确实有效XAML:
SelectionChanged="{x:Bind AccountsSelectionChanged}"
我的视图模型是 public、public、public。我不确定我错过了什么。
任何人都可以提供其他东西来尝试吗?
这是一件很奇怪的事情。我的 MainPage 上有两个 ListView。首先,我有一个 ObservableCollection of Account classes 绑定为 ItemsSource。我还将 SelectionChanged 事件绑定到同一 ViewModel 上的处理程序。这是给我带来麻烦的事件。
在另一个 ListView 上,我想显示文件夹 classes 的 ObservableCollection,selected 帐户的 属性。
<ListView VerticalAlignment="Top"
Margin="0,48,0,0"
ItemsSource="{x:Bind MainVM.SelectedAccount.Folders, Mode=OneWay}"
ItemTemplate="{StaticResource FolderItemTemplate}"
Grid.Row="0">
<ListView.Header>
<TextBlock>Folders</TextBlock>
</ListView.Header>
</ListView>
SelectedAccount 在第一个 ListView 的事件处理程序中重新设置。 我在博客上读到 x:Bind 命令似乎默认为 OneTime 绑定而不是 OneWay,所以我在 ItemsSource 上将 Mode 设置为 OneWay。此绑定将要更改,因此我认为这是一个合适的设置。
然而,这就是我所有问题的根源!我 删除了 Mode=OneWay 设置 并且我的项目编译得很好。奇怪的是,我可以保留此 Mode=OneWay 设置并 删除 另一个 ListView 中的事件绑定,它会编译。我就是不能两者兼得。
我不知道这是否会影响我对这个 ListView 的计划,但至少我现在可以编译了。
EDIT - 这只是答案的一半......我无法使用这些约束进行正确绑定。我需要弄清楚为什么会这样。
编辑 2 我的解决方法是停止使用该事件,而是绑定到 ListView 上的 SelectedItem 属性。 SelectionMode 需要设置为 Single 才能正常工作。此外,SelectedItem 输出一个对象类型,因此我需要设置一个 getter/setter,在将对象传递给私有变量时将其转换为原始帐户 class。当我删除对事件的绑定时,我可以将此 ListView 属性 设置为 Mode=TwoWay 而不会出现任何问题。
编辑 3 实际上有两种解决方法。一般来说,这个总是有效的。只需在代码隐藏中处理事件。由于您的 ViewModel 是代码隐藏上的 public 属性,因此您可以从事件处理程序调用 ViewModel 上的 public 方法并输入相同的参数(或 none ).
//codebehind
//HeadersVM is my ViewModel
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
foreach (var item in e.AddedItems)
HeadersVM.SelectedHeaders.Add((Models.MailHeader)item);
foreach (var item in e.RemovedItems)
HeadersVM.SelectedHeaders.Remove((Models.MailHeader)item);
}
private void BackButton_Click(object sender, RoutedEventArgs e)
{
this.HeadersVM.GoBack();
}
否则,对于特定于 ListView 的 SelectedItem 的解决方法,您可以双向绑定到 SelectedItem 属性。然后,创建一个转换器,其 ConvertBack 方法将对象转换为您的模型。
public class ObjectToAccountConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
if (value != null)
return (Models.Account)value;
return value;
}
}
//in App.xaml Resources
<converters:ObjectToAccountConverter x:Key="ObjectToAccountConverter "/>
//in your Page.xaml
<ListView VerticalAlignment="Top"
Margin="0,48,0,0"
ItemsSource="{x:Bind MainVM.Accounts}"
ItemTemplate="{StaticResource AccountTemplate}"
SelectedItem="{x:Bind MainVM.SelectedAccount, Mode=TwoWay, Converter={StaticResouce ObjectToAccountConverter }}"
Grid.Row="0">
<ListView.Header>
<TextBlock>Folders</TextBlock>
</ListView.Header>
</ListView>
OR 而不是创建转换器来将对象转换回您的模型,您可以将视图模型中的 属性 设为通用对象而不是您的实际对象class:
private Models.Account _selectedAccount = null;
public object SelectedAccount
{
get { return _selectedAccount; }
set
{
if (_selectedAccount != value)
{
_selectedAccount = (Models.Account)value;
RaisePropertyChanged();
RaisePropertyChanged("Folders");
}
}
}