Я столкнулся с этой проблемой и получал все те же сообщения об ошибках при создании самого первого приложения в Visual Studio Professional 2015 (с Xamarin). Не знаю, пригодится ли это кому-нибудь еще, но мы наткнулись на то, что решило проблему для нас.
В MainActivity.cs
есть некоторый код по умолчанию, когда вы впервые открываете проект «Пустое приложение», но мы удалили часть этого кода и скопировали / вставили поверх него. Вот как это выглядит изначально:
namespace App3
{
[Activity(Label = "App3", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
int count = 1;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
// Get our button from the layout resource,
// and attach an event to it
Button button = FindViewById<Button>(Resource.Id.MyButton);
button.Click += delegate { button.Text = string.Format("{0} clicks!", count++); };
}
}
}
Чтобы исправить это: мы попытались вернуть эти строки в код MainActivity.cs
:
[Activity(Label = "App3", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
int count = 1;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
// Get our button from the layout resource,
// and attach an event to it
Button button = FindViewById<Button>(Resource.Id.MyButton);
И затем мы запустили код и ошибка ушла. Возможно, просто глупая ошибка, и она не всегда решит проблему, но она сработала для нас.
Хорошо, мое решение было совершенно ненужным, вот единственные руководства, которые вам когда-либо понадобятся для создания любого пользовательского элемента управления:
Вкратце:
Подкласс некоторого подходящего класса (или UIElement если вам ничего не подходит) - это просто файл * .cs, поскольку мы определяем только поведение, а не внешний вид элемента управления.
public class EnhancedItemsControl : ItemsControl
Добавьте свойство зависимости для ваших «слотов» (обычное свойство недостаточно хорошо, поскольку оно имеет только ограниченную поддержку привязки). Классный трюк: в VS напишите propdp
и нажмите вкладку, чтобы развернуть фрагмент :):
public object AlternativeContent
{
get { return (object)GetValue(AlternativeContentProperty); }
set { SetValue(AlternativeContentProperty, value); }
}
// Using a DependencyProperty as the backing store for AlternativeContent. This enables animation, styling, binding, etc...
public static readonly DependencyProperty AlternativeContentProperty =
DependencyProperty.Register("AlternativeContent" /*name of property*/, typeof(object) /*type of property*/, typeof(EnhancedItemsControl) /*type of 'owner' - our control's class*/, new UIPropertyMetadata(null) /*default value for property*/);
Добавьте атрибут для дизайнера (поскольку вы создаете так называемый элемент управления без внешнего вида), таким образом мы говорим, что нам нужно иметь ContentPresenter с именем PART_AlternativeContentPresenter в нашем шаблоне.
[TemplatePart(Name = "PART_AlternativeContentPresenter", Type = typeof(ContentPresenter))]
public class EnhancedItemsControl : ItemsControl
Предоставьте статический конструктор, который сообщит стилю WPF system о нашем классе (без него стили / шаблоны, нацеленные на наш новый тип, не будут применяться):
static EnhancedItemsControl()
{
DefaultStyleKeyProperty.OverrideMetadata(
typeof(EnhancedItemsControl),
new FrameworkPropertyMetadata(typeof(EnhancedItemsControl)));
}
Если вы хотите что-то сделать с ContentPresenter из шаблона, вы делаете это, переопределив метод OnApplyTemplate:
//remember that this may be called multiple times if user switches themes/templates!
public override void OnApplyTemplate()
{
base.OnApplyTemplate(); //always do this
//Obtain the content presenter:
contentPresenter = base.GetTemplateChild("PART_AlternativeContentPresenter") as ContentPresenter;
if (contentPresenter != null)
{
// now we know that we are lucky - designer didn't forget to put a ContentPresenter called PART_AlternativeContentPresenter into the template
// do stuff here...
}
}
Предоставьте шаблон по умолчанию: всегда в ProjectFolder / Themes / Generic.xaml (у меня есть автономный проект со всеми настраиваемыми универсально используемыми элементами управления wpf, на которые затем ссылаются другие решения). Это единственное место, где система будет искать шаблоны для ваших элементов управления, поэтому поместите здесь шаблоны по умолчанию для всех элементов управления в проекте:
В этом фрагменте я определил новый ContentPresenter, который отображает значение нашего присоединенного свойства AlternativeContent
. Обратите внимание на синтаксис - я мог бы использовать либо
Content = "{Binding AlternativeContent, RelativeSource = {RelativeSource FindAncestor, AncestorType = {x: Type WPFControls: EnhancedItemsControl}}}"
или Content = "{TemplateBinding AlternativeContent}"
, но первый будет работать, если вы определите шаблон внутри своего шаблона (необходимый для стилизации, например, ItemPresenters).
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WPFControls="clr-namespace:MyApp.WPFControls"
>
<!--EnhancedItemsControl-->
<Style TargetType="{x:Type WPFControls:EnhancedItemsControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type WPFControls:EnhancedItemsControl}">
<ContentPresenter
Name="PART_AlternativeContentPresenter"
Content="{Binding AlternativeContent, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type WPFControls:EnhancedItemsControl}}}"
DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type WPFControls:EnhancedItemsControl}}}"
/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Вуаля, вы только что создали свой первый незаметный UserControl (добавьте больше contentpresenters и свойств зависимостей для дополнительных «слотов контента»).
Если вы используете UserControl
, я предполагаю, что вы действительно хотите:
<ContentPresenter Content="{Binding Buttons}"/>
Это предполагает, что DataContext, переданный вашему элементу управления, имеет свойство Buttons.
И с a ControlTemplate
Другой вариант - ControlTemplate, а затем вы можете использовать:
<ContentPresenter ContentSource="Header"/>
Для этого вам потребуется создать шаблон элемента управления, который на самом деле имеет заголовок (обычно HeaderedContentControl).
Hasta la victoria siempre!
Я пришел с рабочим решением (сначала в Интернете, как мне кажется :))
Хитрый DialogControl.xaml.cs - см. Комментарии :
public partial class DialogControl : UserControl
{
public DialogControl()
{
InitializeComponent();
//The Logical tree detour:
// - we want grandchildren to inherit DC from this (grandchildren.DC = this.DC),
// but the children should have different DC (children.DC = this),
// so that children can bind on this.Properties, but grandchildren bind on this.DataContext
this.InnerWrapper.DataContext = this;
this.DataContextChanged += DialogControl_DataContextChanged;
// need to reinitialize, because otherwise we will get static collection with all buttons from all calls
this.Buttons = new ObservableCollection<FrameworkElement>();
}
void DialogControl_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
/* //Heading is ours, we want it to inherit this, so no detour
if ((this.GetValue(HeadingProperty)) != null)
this.HeadingContainer.DataContext = e.NewValue;
*/
//pass it on to children of containers: detours
if ((this.GetValue(ControlProperty)) != null)
((FrameworkElement)this.GetValue(ControlProperty)).DataContext = e.NewValue;
if ((this.GetValue(ButtonProperty)) != null)
{
foreach (var control in ((ObservableCollection<FrameworkElement>) this.GetValue(ButtonProperty)))
{
control.DataContext = e.NewValue;
}
}
}
public FrameworkElement Control
{
get { return (FrameworkElement)this.GetValue(ControlProperty); }
set { this.SetValue(ControlProperty, value); }
}
public ObservableCollection<FrameworkElement> Buttons
{
get { return (ObservableCollection<FrameworkElement>)this.GetValue(ButtonProperty); }
set { this.SetValue(ButtonProperty, value); }
}
public string Heading
{
get { return (string)this.GetValue(HeadingProperty); }
set { this.SetValue(HeadingProperty, value); }
}
public static readonly DependencyProperty ControlProperty =
DependencyProperty.Register("Control", typeof(FrameworkElement), typeof(DialogControl));
public static readonly DependencyProperty ButtonProperty =
DependencyProperty.Register(
"Buttons",
typeof(ObservableCollection<FrameworkElement>),
typeof(DialogControl),
//we need to initialize this for the designer to work correctly!
new PropertyMetadata(new ObservableCollection<FrameworkElement>()));
public static readonly DependencyProperty HeadingProperty =
DependencyProperty.Register("Heading", typeof(string), typeof(DialogControl));
}
И DialogControl.xaml (без изменений):
<UserControl x:Class="TkMVVMContainersSample.Views.Common.DialogControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"
>
<DockPanel x:Name="InnerWrapper">
<DockPanel
LastChildFill="False"
HorizontalAlignment="Stretch"
DockPanel.Dock="Bottom">
<ItemsControl
x:Name="ButtonsContainer"
ItemsSource="{Binding Buttons}"
DockPanel.Dock="Right"
>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Padding="8">
<ContentPresenter Content="{TemplateBinding Content}" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Margin="8">
</StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DockPanel>
<Border
Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"
Padding="8,0,8,8"
>
<StackPanel>
<Label
x:Name="HeadingContainer"
Content="{Binding Heading}"
FontSize="20"
Margin="0,0,0,8" />
<ContentPresenter
x:Name="ControlContainer"
Content="{Binding Control}"
/>
</StackPanel>
</Border>
</DockPanel>
</UserControl>
Пример использования:
<Window x:Class="TkMVVMContainersSample.Services.TaskEditDialog.ItemEditView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Common="clr-namespace:TkMVVMContainersSample.Views.Common"
Title="ItemEditView"
>
<Common:DialogControl>
<Common:DialogControl.Heading>
Edit item
</Common:DialogControl.Heading>
<Common:DialogControl.Control>
<!-- Concrete dialog's content goes here -->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0">Name</Label>
<TextBox Grid.Row="0" Grid.Column="1" MinWidth="160" TabIndex="1" Text="{Binding Name}"></TextBox>
<Label Grid.Row="1" Grid.Column="0">Phone</Label>
<TextBox Grid.Row="1" Grid.Column="1" MinWidth="160" TabIndex="2" Text="{Binding Phone}"></TextBox>
</Grid>
</Common:DialogControl.Control>
<Common:DialogControl.Buttons>
<!-- Concrete dialog's buttons go here -->
<Button Width="80" TabIndex="100" IsDefault="True" Command="{Binding OKCommand}">OK</Button>
<Button Width="80" TabIndex="101" IsCancel="True" Command="{Binding CancelCommand}">Cancel</Button>
</Common:DialogControl.Buttons>
</Common:DialogControl>
</Window>