问题描述
大家好,新年快乐! 我一直在寻找很多没有找到答案。所以我的问题是为什么 ListView、CarouselView、ScrollView 元素“隐藏”了它的子元素?为了澄清测试,我放置了一个简单的网格并添加了一些单选按钮 (x:name="radButton1") 和相应的标签 (x:name="label1")(冗余但单选按钮当前不显示其文本值)和图像。从后面的代码中,我可以使用 radButton1.GroupName、label1.Text 等访问它们,没有问题。但是,一旦我将它们移动到我的 ListView、CarouselView、ScrollView 并返回到后面的代码,我就会收到 radButton1、label1、image 等错误,它们不再在当前上下文中无法通过 Name 值检索? 我试图获取 listview 元素,然后查看 children 但这并没有向我显示这些元素,以便我可以像那里文本值或 IsVisible 等那样修改它们。在这一点上,我真的只关心 CarouselView是什么让我在用户交互中拥有更好的外观和感觉。
<Image x:Name="greenCheck" Source="Greencheckmark.gif" IsVisible="{Binding GreenCheck}"></Image>
<Image x:Name="GrayCheck" Source="Graycheckmark.gif" IsVisible="{Binding GrayCheck}"></Image>
<Image x:Name="greenCheck1" Source="Greencheckmark.gif" IsVisible="{Binding GreenCheck1}"></Image>
<Image x:Name="GrayCheck1" Source="Graycheckmark.gif" IsVisible="{Binding GrayCheck1}"></Image>
Codebehind:
GrayCheck = false;
GreenCheck = true;
GrayCheck1 = true;
GreenCheck1 = false;
TIA! 干杯! 瑞克...
解决方法
因为所有这些控件都是模板化的。您无法按名称访问模板化元素。
如果您的页面上只有一个 Label
并在 XAML 中为其分配一个 x:Name
myLabel,则 XAML 编译器会创建一个名为 myLabel的变量> 您可以使用它从背后的代码中引用该控件。
但是,如果您的 ListView
在其模板中包含 Label
,则可能会在运行时生成该 Label
的 0、12 或 1000 个副本,具体取决于ItemsSource
中的项目数。您不能通过名称来引用它,因为它不是单个实例,而是 0 到多个实例。
您应该使用数据绑定将 UI 的属性与 ViewModel 相关联,并在运行时更新您的 ViewModel 以更改您的 UI。这是 MVVM 模式的一部分。您不应在运行时直接修改模板化控件的 UI 属性。
,但是,一旦我将它们移动到我的 ListView、CarouselView、ScrollView 并返回到后面的代码,我就会收到 radButton1、label1、image 等错误,它们不再在当前上下文中无法通过 Name 值检索?
正如 Jason 所说,你不能在 ListView 模板中通过 Name 访问控件,你可以通过 viewmodel 更改控件值。
<StackLayout>
<ListView
x:Name="listview"
HasUnevenRows="True"
ItemsSource="{Binding radiomodels}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<RadioButton
x:Name="radiobutton1"
GroupName="images"
Text="{Binding radiobutton1text}" />
<RadioButton
x:Name="radiobutton2"
GroupName="images"
Text="{Binding radiobutton2text}" />
<Switch x:Name="switch" IsToggled="{Binding ischeck,Mode=TwoWay}" />
<Image IsVisible="{Binding Path=IsToggled,Source={x:Reference switch}}" Source="{Binding image}" />
<Label Text="this is test" />
<Button
x:Name="btn1"
Clicked="btn1_Clicked"
Text="button" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button
x:Name="btnupdate"
Clicked="btnupdate_Clicked"
Text="update listview item" />
</StackLayout>
public partial class Page1 : ContentPage
{
public ObservableCollection<radiomodel> radiomodels { get; set; }
public Page1()
{
InitializeComponent();
radiomodels = new ObservableCollection<radiomodel>()
{
new radiomodel(){radiobutton1text="radio button1",radiobutton2text="radio button2",ischeck=false,image="a5.jpg"},new radiomodel(){radiobutton1text="radio button1",image="a6.jpg"},image="a7.jpg"},image="a8.jpg"},image="a9.jpg"}
};
this.BindingContext = this;
}
private void btnupdate_Clicked(object sender,EventArgs e)
{
radiomodel item = (radiomodel)listview.SelectedItem;
var changeitem = radiomodels.FirstOrDefault(x => x.image == item.image);
if(changeitem!=null)
{
changeitem.radiobutton1text = "test";
}
}
}
public class radiomodel:ViewModelBase
{
private string _radiobutton1text;
public string radiobutton1text
{
get { return _radiobutton1text; }
set
{
_radiobutton1text = value;
RaisePropertyChanged("radiobutton1text");
}
}
private string _radiobutton2text;
public string radiobutton2text
{
get { return _radiobutton2text; }
set
{
_radiobutton2text = value;
RaisePropertyChanged("radiobutton2text");
}
}
private bool _ischeck;
public bool ischeck
{
get { return _ischeck; }
set
{
_ischeck = value;
RaisePropertyChanged("ischeck");
}
}
public string image { get; set; }
}
}
如果你还想在ListView中获取控件,可以按照下面的代码获取ListView选中的行控件。
private void btn1_Clicked(object sender,EventArgs e)
{
Button button = sender as Button;
StackLayout stacklayout =(StackLayout) button.Parent;
RadioButton radiobutton1 = (RadioButton)stacklayout.Children[0];
radiobutton1.Text = "test";
}
ViewModelBase 是类,实现 INotifyPropertyChanged 接口,通知数据更新。
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this,new PropertyChangedEventArgs(propertyName));
}
}
}