У меня возникла проблема, когда datagrid не отражает изменения в своей коллекции при прикреплении к представлению внутри представления. Точнее, у меня есть SecondView в MainView. На SecondView у меня есть datagrid с автогенераторами, установленными в true; когда сначала отображается рендеринг данных, он отображает соответствующие столбцы и заголовки. Однако, когда я заполняю список, который прикреплен к нему, изменения не отражаются.Просмотр в представлении, не обновляющемся - Caliburn.Micro
Вот полный код для двух мнений и их соответствующих ViewModels: MainWindowView:
<Window x:Class="MyApp.MainWindowView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:cal="http://www.caliburnproject.org"
xmlns:views="clr-namespace:MyApp"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindowView" Height="300" Width="300">
<Grid>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="File">
<MenuItem Header="Open" x:Name="Open"/>
<MenuItem Header="Exit" x:Name="Exit"/>
</MenuItem>
</Menu>
<StackPanel DockPanel.Dock="Bottom">
<views:SecondView/>
</StackPanel>
</DockPanel>
</Grid>
MainWindowViewModel:
namespace MyApp
{
[Export(typeof(IShell))]
internal class MainWindowViewModel : Screen, IShell
{
Regex expression = new Regex(@"^N\d\.C\d\.D\d\.R\d:\s\s\s-\d"); //ex. "N1.C1.D2.R1: -3"
SecondViewModel svm = new SecondViewModel();
public void Open()
{
Microsoft.Win32.OpenFileDialog openFile = new Microsoft.Win32.OpenFileDialog();
openFile.Multiselect = true;
openFile.Filter = "Text Files(*.txt)|*.txt|Log Files(*.log)|*.log|All Files(*.*)|*.*";
openFile.Title = "Open File(s)";
bool? userClickedOK = openFile.ShowDialog();
string[] _fileNames = openFile.FileNames;
if (userClickedOK == true)
{
if (_fileNames != null)
{
for (int i = 0; i < _fileNames.Length; i++)
{
ValidFiles(_fileNames[i]);
}
}
}
}
public void Exit()
{
App.Current.Shutdown();
}
/* ValidFiles() accepts a string containing a filename and creates a Streamreader that reads the file if it is not a Boxboro file.
*/
public void ValidFiles(string filename)
{
string line;
using (StreamReader sr = new StreamReader(filename))
{
while ((line = sr.ReadLine()) != null)
{
if (line.Contains("Mono Status"))
{
Console.WriteLine("File(s) not supported by this parser. Please select a valid file.");
break;
}
else
{
IsMatch(line);
}
}
}
}
/* IsMatch() accepts a string "input" and determines which parsing method to send the string to, if any.
* Strings not matching any of the initial criteria are not processed to limit overhead.
*/
public void IsMatch(string input)
{
Match match = expression.Match(input);
if (match.Success)
{
svm.GetData(input);
}
}
}
}
SecondWindowView:
<UserControl x:Class="MyApp.SecondView"
xmlns:cal="http://www.caliburnproject.org"
cal:Bind.Model="MyApp.SecondViewModel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<StackPanel>
<DataGrid x:Name="MyList"/>
</StackPanel>
</Grid>
SecondWindowViewModel:
namespace MyApp
{
[Export(typeof(SecondViewModel))]
class SecondViewModel:Screen
{
Parse parse = new Parse();
BindableCollection<MyObject> myList = new BindableCollection<MyObject>();
MyObject myObject;
public MyObject MyObject
{
get { return myObject; }
set
{
myObject = value;
NotifyOfPropertyChange(() => MyList);
}
}
public BindableCollection<MyObject> MyList
{
get { return myList; }
set
{
MyList = value;
NotifyOfPropertyChange(() => MyList);
}
}
public void GetData(string input)
{
string[] tempArray = input.Split();
List<int> tempList = new List<int>();
for (int i = 1; i < tempArray.Length; i++)
{
if (!string.IsNullOrEmpty(tempArray[i]))
{
tempList.Add(Convert.ToInt32(tempArray[i]));
}
}
int[] tempIntArray = tempList.ToArray();
MyObject = new MyObject(tempArray[0], tempIntArray[0], tempIntArray[1], tempIntArray[2], tempIntArray[3]);
this.MyList.Add(MyObject);
Console.WriteLine("MyList has " + MyList.Count.ToString() + " elements.");
//foreach (MyObject item in MyList)
//{
// Console.WriteLine(item.Location);
//}
}
}
}
Boostrapper:
namespace MyApp
{
internal class AppBootStrapper : Bootstrapper<IShell>
{
static AppBootStrapper()
{
//Initializes the logger for debugging, remove or comment out in release.
LogManager.GetLog = type => new DebugLogger(type);
}
private CompositionContainer container;
protected override void BuildUp(object instance)
{
this.container.SatisfyImportsOnce(instance);
}
protected override void Configure()
{
this.container =
new CompositionContainer(
new AggregateCatalog(
AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()));
var batch = new CompositionBatch();
batch.AddExportedValue<IWindowManager>(new WindowManager());
batch.AddExportedValue<IEventAggregator>(new EventAggregator());
batch.AddExportedValue(this.container);
this.container.Compose(batch);
}
protected override IEnumerable<object> GetAllInstances(Type serviceType)
{
return this.container.GetExportedValues<object>(AttributedModelServices.GetContractName(serviceType));
}
//This method is required for the BootStrapper.cs to be discovered.
protected override object GetInstance(Type serviceType, string key)
{
string contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(serviceType) : key;
IEnumerable<object> exports = this.container.GetExportedValues<object>(contract);
if (exports.Count() > 0)
{
return exports.First();
}
throw new Exception(string.Format("Could not locate any instances of contract {0}.", contract));
}
}
}
Основываясь на моем понимании Caliburn.Micro, после обновления ObservableCollection MyList (а новый em добавлено), datagrid с x: name MyList должен быть обновлен. Даже без шаблона данных я бы подумал, что я увижу список пустых записей, эквивалентных по длине количеству объектов в MyList. Когда я использую этот же код в MainViewModel, а не в usercontrol, привязанный к MainView, у меня нет проблем с отображением списка. Кажется, что мне не хватает чего-то об обновлении вида в представлении.
Следует отметить, что я могу проверить, что в списке есть объекты в нем с помощью Console.WriteLine (MyList.Count.ToString()) и просмотра выходного окна. Я ненавижу спрашивать об этих вещах, каждый раз, когда я это делаю, это опечатка или что-то в равной степени глупо, но я слишком долго застрял здесь.
ПРИМЕЧАНИЕ: Даже с включенным MyList.Refresh() на каждой итерации изменений в datagrid не происходит.
ПРИМЕЧАНИЕ: Похоже, что это может ответить на мой вопрос, но я не понимаю, как его реализовать. Возможно, если кто-то еще лучше это понимает, они могут поместить строки кода в соответствующие места в моем коде и объяснить, почему это работает. Заранее спасибо. Caliburn.Micro convention-based bindings not working in nested views?
Чтобы дать соответствующий контекст: Я использовал C# .NET, так 1.1, но никогда не WPF. Если вы застряли, попробуйте это: установите ** очень простое ** демо-приложение в качестве доказательства концепции. Чем меньше кода, тем лучше. Вы можете найти ответ на свой вопрос. Просто мысль. – Pressacco
@Pressaco, я ценю совет. Это, по сути, расширенная версия простого демонстрационного приложения. Моя первая версия была функциональной демонстрацией, которую я заимствовал, а затем расширился. В этой итерации я пытаюсь реализовать несколько представлений, чтобы я мог постепенно добавлять fucntionality в представления, не беспокоясь о влиянии на приложение в целом. – spugm1r3
Чтобы дать соответствующий контекст, я использовал C# около 6 месяцев, wpf около 3 и Caliburn.Micro в течение нескольких недель :) – spugm1r3