#c# #silverlight
#c# #silverlight
Вопрос:
Пожалуйста, проанализируйте этот код.. Я подумал, что мы можем объединить метку и элемент управления в один общий элемент управления. Я реализую таким образом:
//my class
public partial class WrappingControl : UserControl
{
public string MyLabel { get { return lb.Text; } set { lb.Text = value; } }
public UIElement MyControl { get { return uc.Content; } set { uc.Content = value; } }
public T CastControl<T>()
{
return (T)Convert.ChangeType(MyControl, typeof(T), null);
}
}
//silverlight class
public partial class WrappingControl : UserControl
{
TextBlock lb;
UserControl uc;
}
и я могу использовать, с чем-то вроде этого:
var wc =new WrappingControl();
wc.MyLabel = "ID:";
wc.MyControl = new TextBox();
wc.CastControl<TextBox>().Text="123";
var wc2 = new WrappingControl();
wc2.MyLabel = "Is Ok?:";
wc2.MyControl = new CheckBox();
wc2.CastControl<CheckBox>().IsChecked = true;
Единственным недостатком является то, что я вынужден повторять, какой тип элемента управления я хочу, но мне интересно, есть ли способ (возможно, путем отражения) определить тип элемента управления и вернуть объект этого типа и получить для этого intellisense. Нравится:
wc.ActualControl.Text = "123";
wc2.ActualControl.IsChecked = true;
Ответ №1:
Если вы используете C # 4 и .NET 4, вы могли бы просто использовать динамическую типизацию. Измените свой тип свойства на dynamic
, и вы ушли:
wc.WrappedControl = new CheckBox();
wc.WrappedControl.IsChecked = true;
Обратите внимание, что вы не можете определить тип времени выполнения элемента управления и ожидать, что это повлияет на типы времени компиляции.
Рассматривали ли вы возможность использования дженериков?
public partial class WrappingControl<T> : UserControl where T : UIElement
{
public T WrappedControl { get; set; } // Add appropriate logic
}
var wc2 = new WrappingControl<CheckBox>();
wc2.WrappedControl = new CheckBox();
wc2.WrappedControl.IsChecked = true;
Если вы также зададите T
new()
ограничение, WrappingControl
можно даже создать вложенный элемент управления.
Другой альтернативой является использование инициализатора объекта, чтобы избежать необходимости часто ссылаться на элемент управления:
var wc = new WrappedControl
{
MyLabel = "Test",
MyControl = new CheckBox { IsChecked = true }
};
Комментарии:
1. XAML для Silverlight не обрабатывает общие элементы управления, если они используются в разметке XAML. Конечно, XAML 2009 поддерживает дженерики, но только в виде отдельных документов. Если это только для кода, то дженерики, безусловно, будут работать.
2. @vcsjones: Похоже, что это используется из code-behind больше, чем XAML, но ваша точка зрения принята.
3. Первая идея использования dynamic решит проблему, другая идея не очень полезна, потому что XAML не допускает generic, а последняя вообще не решает проблему, заключающуюся в том, как читать / записывать свойства элемента управления после его создания (с помощью XAML).
Ответ №2:
Я думаю, Джон дал вам ответ. Однако вы можете рассмотреть возможность использования шаблонного элемента управления, основанного на ContentControl
, а не на UserControl
. Вот начало для 10.
Добавьте новый элемент управления с шаблоном Silverlight в свой проект, назовите его «LabeledControl».
Измените файл .cs create так, чтобы он выглядел следующим образом:-
public class LabeledControl : ContentControl
{
public LabeledControl()
{
this.DefaultStyleKey = typeof(LabeledControl);
}
#region public string Label
public string Label
{
get { return GetValue(LabelProperty) as string; }
set { SetValue(LabelProperty, value); }
}
public static readonly DependencyProperty LabelProperty =
DependencyProperty.Register(
"Label",
typeof(string),
typeof(LabeledControl),
new PropertyMetadata(null));
#endregion public string Label
}
Вы заметите, что все, что мы сделали, это изменили наследуемый класс ContentControl
и добавили свойство зависимости «Label».
Теперь откройте файл Themes / Generic.xaml и найдите стиль по умолчанию для этого элемента управления. Замените его этим:-
<Style TargetType="local:LabeledControl">
<Setter Property="Foreground" Value="#FF000000"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Top"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:LabeledControl">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Text="{TemplateBinding Label}" />
<ContentPresenter
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Cursor="{TemplateBinding Cursor}"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Все, что мы здесь сделали, это скопировали исходный стиль для ContentControl
и завернули его в a Grid
, чтобы мы могли поместить a TextBlock
, который мы привязываем к Label
свойству.
Вы, вероятно, уже заметили, что ничто из этого на самом деле не решает «проблему», которую вы хотели решить. Я просто указываю на гораздо более «Silverlight-esq» подход к созданию составных элементов управления, он более гибкий.
Что касается вашей конкретной проблемы, я бы сказал, что на самом деле это не проблема, в последнем примере Джона он показывает, как вы можете создать свой код, чтобы избежать дублирования. С приведенным выше элементом управления этот код будет выглядеть следующим образом:-
var lc = new LabeledControl
{
Label = "Check this:",
Content = new CheckBox {IsChecked = True}
};
ИЛИ в Xaml:-
<local:LabeledControl Label="Check this:">
<CheckBox IsChecked="True" />
</local>
Как указывает vcsjones Джону, использование универсального класса — не очень дружественный к Silverlight подход, я бы этого избегал.