Populate my ListView with item source from class - wpf

I have this Singleton that hold my ObservableCollection<MyData> as a memeber:
public sealed class Singleton
{
private static volatile Singleton instance;
private static object syncRoot = new Object();
public ObservableCollection<MyData> Files { get; private set; }
private Singleton()
{
Files = new ObservableCollection<MyData>();
}
public static Singleton Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
instance = new Singleton();
}
}
return instance;
}
}
}
Declaration from main form class:
ObservableCollection<MyData> Files;
And here after the constructor:
Files= Singleton.Instance.Files;
XAML:
<ListView ItemsSource="{Binding Files}" />
Now when the user choose files i want to check each file:
private static void Check(IEnumerable<string> files)
{
CancellationTokenSource tokenSource = new CancellationTokenSource();
CancellationToken token = tokenSource.Token;
Task task = Task.Factory.StartNew(() =>
{
try
{
Parallel.ForEach(files,
new ParallelOptions
{
MaxDegreeOfParallelism = 1
},
file =>
{
ProcessFile(file);
});
}
catch (Exception)
{ }
}, tokenSource.Token,
TaskCreationOptions.None,
TaskScheduler.Default).ContinueWith
(t =>
{
}
, TaskScheduler.FromCurrentSynchronizationContext()
);
}
And:
private static void ProcessFile(string file)
{
// Lets assume that i want to add this file into my `ListView`
MyData data = new .....
Singleton.Instance.Files.Add(data);
}
So after this point when i am add files into my list nothing happenning.

Using your code above i was able to reproduce the issue you describe.
The problem is that WPF cannot bind to fields, see this question for more details. All you need to do is to change the ObservableCollection<MyData> in the code behind of your main form to a property instead of a field.
public partial class MainWindow : Window
{
public ObservableCollection<MyData> Files { get; private set; }

Related

Problem loading view with MEF and ExportAttribute

I have a WPF app and I'm trying to use MEF to load viewmodels and view.
I can't successfully load Views.
The code:
public interface IContent
{
void OnNavigatedFrom( );
void OnNavigatedTo( );
}
public interface IContentMetadata
{
string ViewUri { get; }
}
[MetadataAttribute]
public class ExtensionMetadataAttribute : ExportAttribute
{
public string ViewUri { get; private set; }
public ExtensionMetadataAttribute(string uri) : base(typeof(IContentMetadata))
{
this.ViewUri = uri;
}
}
class ViewContentLoader
{
[ImportMany]
public IEnumerable<ExportFactory<IContent, IContentMetadata>> ViewExports
{
get;
set;
}
public object GetView(string uri)
{
// Get the factory for the View.
var viewMapping = ViewExports.FirstOrDefault(o =>
o.Metadata.ViewUri == uri);
if (viewMapping == null)
throw new InvalidOperationException(
String.Format("Unable to navigate to: {0}. " +
"Could not locate the View.",
uri));
var viewFactory = viewMapping.CreateExport();
var view = viewFactory.Value;
return viewFactory;
}
}
I supposed to use this code like this:
1)Decorate a User control
[Export(typeof(IContent))]
[ExtensionMetadata("CustomPause")]
[PartCreationPolicy(System.ComponentModel.Composition.CreationPolicy.NonShared)]
public partial class CustomPause : Page , IContent, IPartImportsSatisfiedNotification
{
public CustomPause()
{
InitializeComponent();
}
}
2) Compose the parts:
var cv = new CompositionContainer(aggregateCatalog);
var mef = new ViewContentLoader();
cv.ComposeParts(mef);
3) Load the view at runtime given a URI, for example:
private void CustomPause_Click(object sender, RoutedEventArgs e)
{
var vc = GlobalContainer.Instance.GetMefContainer() as ViewContentLoader;
MainWindow.MainFrame.Content = vc.GetView ("CustomPause");
}
Problem is this line in the GetView method fails:
var viewMapping = ViewExports.FirstOrDefault(o =>
o.Metadata.ViewUri == uri);
The query fails and so viewMapping is null but composition seems ok and I can see that ViewExports contains an object of type:
{System.ComponentModel.Composition.ExportFactory<EyesGuard.MEF.IContent, EyesGuard.MEF.IContentMetadata>[0]
I don't know where I'm wrong. Do you have a clue?
Gianpaolo
I had forgot this
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
in the MetadataAttribute

My application usage memory remained high even after clear all my objects list

So i have this Base Class:
public abstract class WiresharkFile : IDisposable
{
private string _fileName;
private int _packets;
private int _packetsSent;
private string _duration;
private double _speed;
private int _progress;
protected abstract WiresharkFilePacket ReadPacket();
public abstract IEnumerator<WiresharkFilePacket> GetEnumerator();
public abstract void Rewind();
public string FileName
{
get { return _fileName; }
set { _fileName = value; }
}
public int Packets
{
get { return _packets; }
set { _packets = value; }
}
public void Dispose()
{
// implemented inside sub class.
}
}
And specific Wireshark format (libpcap):
public class Libpcap : WiresharkFile, IDisposable, IEnumerable<WiresharkFilePacket>
{
private BinaryReader binaryReader;
private Version version;
private uint snaplen;
private int thiszone;
private uint sigfigs;
private LibpcapLinkType linktype;
private long basePos;
private bool byteSwap;
private static uint MAGIC = 0xa1b2c3d4;
private static uint MAGIC_ENDIAN = 0xd4c3b2a1;
public Libpcap(string path)
: this(new FileStream(path, FileMode.Open, FileAccess.Read))
{
FileName = path;
}
private Libpcap(Stream fileStream)
{
...
}
public override void Rewind()
{
binaryReader = new BinaryReader(new FileStream(FileName, FileMode.Open, FileAccess.Read));
binaryReader.BaseStream.Position = basePos;
}
public void Dispose()
{
if (binaryReader != null)
binaryReader.Close();
}
I removed almost all parts of how i am read this file
Add files in to my application
I have this objects list:
public ObservableCollection<WiresharkFile> wiresharkFiles { get; set; }
This list is binding into my ListView.
When the user choose files to add into my application:
string[] files = openFileDialog.FileNames;
I am check this files via another class:
public class FileValidation
{
public static void DoWork(IEnumerable<string> files)
{
CancellationTokenSource tokenSource = new CancellationTokenSource();
CancellationToken token = tokenSource.Token;
Task task = Task.Factory.StartNew(() =>
{
try
{
Parallel.ForEach(files,
new ParallelOptions
{
MaxDegreeOfParallelism = 3
},
file =>
{
ProcessFile(file);
});
}
catch (Exception)
{ }
}, tokenSource.Token,
TaskCreationOptions.None,
TaskScheduler.Default).ContinueWith
(t =>
{
if (FinishValidationEventHandler != null)
FinishValidationEventHandler();
}
, TaskScheduler.FromCurrentSynchronizationContext()
);
}
private static void ProcessFile(string file)
{
ReadWiresharkFormat(file);
using (WiresharkFile wiresharkFile = new Libpcap(file))
{
WiresharkFileInfo.ReadInfo(wiresharkFile);
// Add file into my list.
}
}
private static WiresharkFileFormat ReadWiresharkFormat(string file)
{
using (BinaryReader binaryReader = new BinaryReader(File.Open(file, FileMode.Open, FileAccess.Read)))
{
// Open file and read first 4 bytes in order to verify file type.
}
}
private static void ReadInfo(WiresharkFile wiresharkFile)
{
foreach (WiresharkFilePacket packet in wiresharkFile)
{
// Collect file information (number of packets...)
}
}
}
OK so until here all good.
Now when add many files, lets say (1000+-) i can see that my memory usage is growing in 200MB but after clear this list the memory usage not changed.
Any idea what could cause this ?

Cannot bind to the property or column States on the DataSource

Why this work :
public Form1()
{
InitializeComponent();
exCheckedListBox1.DataSource = Profiles;
this.exCheckedListBox1.DataBindings.Add(new System.Windows.Forms.Binding("Tag", this, "States", true));
}
CheckedBindingList Profiles = new CheckedBindingList();
public int States
{
get
{
return Profiles.States;
}
set
{
Profiles.States = value;
}
}
}
public class CheckedBindingList : List<string>
{
public int States { get; set; }
}
but when change binding to
this.exCheckedListBox1.DataBindings.Add(new System.Windows.Forms.Binding("Tag", this.Profiles, "States", true));
throw the Exception ?
Thanks all very very very. I try to bind filed from my custom list class that inherit form List.
Exception - Cannot bind to the property or column States on the DataSource.
Parameter name: dataMember
Seems System.Windows.Forms.Binding parameter dataSource cannot be a class that inherits from List< T >
This solves the problem:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Load += new EventHandler(Form1_Load);
}
CheckedBindingList Profiles = new CheckedBindingList();
SomeClass some_class = new SomeClass();
public int States
{
get
{
return Profiles.States;
}
set
{
Profiles.States = value;
}
}
private void Form1_Load(object sender, EventArgs e)
{
exCheckedListBox1.DataSource = Profiles;
exCheckedListBox1.DataBindings.Add(new System.Windows.Forms.Binding("Tag", some_class, "States", true));
}
}
public class CheckedBindingList : List<string>
{
public int States { get; set; }
}
public class SomeClass
{
public int States { get; set; }
}

What is the right way to save and restore a disconnected entity using code first?

So that I can store the user's screen preferences, I have ScreenSettings entity that I want to retrieve when the program starts and save when the program ends.
For this reason I don't want to keep the context open.
I am wondering about the best way to do this.
I have tried the following
however I am not comfortable with the SaveSettings function because it deletes and re-adds the object.
How do I save changes to the object without actually replacing it?
namespace ClassLibrary1
{
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
//Domain Class
public class ScreenSetting
{
#region Properties
public int Id { get; set; }
[Required]
public int WindowLeft { get; set; }
[Required]
public int WindowTop { get; set; }
#endregion
}
// Context
public class Context : DbContext
{
#region Properties
public DbSet<ScreenSetting> ScreenSettings { get; set; }
#endregion
}
// UI
public class UI
{
#region Public Methods
// Get the settings object
public ScreenSetting GetSettings(int SettingsId)
{
var Db = new Context();
ScreenSetting settings = Db.ScreenSettings.Find(SettingsId);
if (settings == null)
{
settings = new ScreenSetting { Id = SettingsId, WindowTop = 100, WindowLeft = 100 };
Db.ScreenSettings.Add(settings);
}
Db.Dispose();
return settings;
}
// Save the settings object
public void SaveSettings(ScreenSetting settings)
{
var Db = new Context();
ScreenSetting oldSettings = Db.ScreenSettings.Find(settings.Id);
if (oldSettings == null)
{
Db.ScreenSettings.Add(settings);
}
else
{
Db.ScreenSettings.Remove(oldSettings);
Db.ScreenSettings.Add(settings);
}
Db.Dispose();
}
public void test()
{
ScreenSetting setting = this.GetSettings(1);
setting.WindowLeft = 500;
setting.WindowTop = 500;
this.SaveSettings(setting);
}
#endregion
#region Methods
private static void Main()
{
var o = new UI();
o.test();
}
#endregion
}
}
You ran into a common pattern, update or insert, which is so common that it's got a name: upsert. When a pattern is common, usually there also is a common solution.
In System.Data.Entity.Migrations there is an extension method AddOrUpdate that does exactly what you want:
public void SaveSettings(ScreenSetting settings)
{
using (var db = new Context())
{
db.ScreenSettings.AddOrUpdate(settings);
db.SaveChanges();
}
}

Injecting Commands into ViewModels

I'm trying to figure out what is the right way to inject an ICommand into my ViewModel.
Given that my ViewModel looks like this.
public class ViewModel : IViewModel
{
ICommand LoadCommand { get; }
ICommand SaveCommand { get; }
}
I currently do this in my constructor
public ViewModel(IRepository repository, IErrorLog errorLog, IValidator validator)
{
LoadCommand = new LoadCommandImpl(repository, errorLog);
SaveCommand = new SaveCommandImpl(repository, errorLog, validator);
}
Note that the parameters are not used by the ViewModel at all, aside from constructing the commands.
While I try to contain as much of the logic as possible in the injected interfaces, there is still logic in the commands.
It would seem more appropriate to do this
public ViewModel(ICommand loadCommand, ICommand saveCommand)
{
LoadCommand = loadCommand;
SaveCommand = saveCommand;
LoadCommand.SetViewModel(this);
SaveCommand.SetViewModel(this);
}
However to do this, I would need to make my Unity registrations like this. Which isn't the end of the world, but it seems like a pain.
container.RegisterType<ICommand, LoadCommandImpl>("loadCommand");
container.RegisterType<ICommand, SaveCommandImpl>("saveCommand");
container.RegisterType<IViewModel, ViewModel>(
new InjectionConstructor(
new ResolvedParameter<ICommand>("loadCommand"),
new ResolvedParameter<ICommand>("SaveCommand")));
Alternatively, I could make ILoadCommand and ISaveCommand interfaces, but these interfaces would be empty or might implement ICommand.
I'm not a huge fan of any of these solutions. What is the recommended approach here?
Edit in response to blindmeis
Let's pretend this is something other than commands for a moment.
public ViewModel(IFoo foo)
{
Bar = new Bar(foo);
}
In my opinion, it would be more appropriate to just inject IBar
public ViewModel(IBar bar)
{
Bar = bar;
}
But now I have Bar1 and Bar2. So I can either do
public ViewModel(IFoo foo)
{
Bar1 = new Bar1(foo);
Bar2 = new Bar2(foo);
}
or
public ViewModel(IBar bar1, IBar bar2)
{
Bar1 = bar1;
Bar2 = bar2;
}
This behavior is not included in Unity but its not hard to retrofit.
var container = new UnityContainer();
container.AddNewExtension<MapParameterNamesToRegistrationNamesExtension>();
container.RegisterType<ICommand, LoadCommand>("loadCommand");
container.RegisterType<ICommand, SaveCommand>("saveCommand");
container.RegisterType<ViewModel>(new MapParameterNameToRegistrationName());
var vm = container.Resolve<ViewModel>();
Assert.IsType(typeof(LoadCommand), vm.LoadCommand);
Assert.IsType(typeof(SaveCommand), vm.SaveCommand);
public class MapParameterNamesToRegistrationNamesExtension : UnityContainerExtension
{
protected override void Initialize()
{
var strategy = new MapParameterNamesToRegistrationNamesStrategy();
this.Context.Strategies.Add(strategy, UnityBuildStage.PreCreation);
}
}
public class MapParameterNamesToRegistrationNamesStrategy : BuilderStrategy
{
public override void PreBuildUp(IBuilderContext context)
{
if (context.Policies.Get<IMapParameterNameToRegistrationNamePolicy>(context.BuildKey) == null)
{
return;
}
IPolicyList resolverPolicyDestination;
IConstructorSelectorPolicy selector = context.Policies.Get<IConstructorSelectorPolicy>(context.BuildKey, out resolverPolicyDestination);
var selectedConstructor = selector.SelectConstructor(context, resolverPolicyDestination);
if (selectedConstructor == null)
{
return;
}
var parameters = selectedConstructor.Constructor.GetParameters();
var parameterKeys = selectedConstructor.GetParameterKeys();
for (int i = 0; i < parameters.Length; i++)
{
Type parameterType = parameters[i].ParameterType;
if (parameterType.IsAbstract || parameterType.IsInterface)
{
IDependencyResolverPolicy resolverPolicy = new NamedTypeDependencyResolverPolicy(parameterType, parameters[i].Name);
context.Policies.Set<IDependencyResolverPolicy>(resolverPolicy, parameterKeys[i]);
}
}
resolverPolicyDestination.Set<IConstructorSelectorPolicy>(new SelectedConstructorCache(selectedConstructor), context.BuildKey);
}
}
public class MapParameterNameToRegistrationName : InjectionMember
{
public override void AddPolicies(Type serviceType, Type implementationType, string name, IPolicyList policies)
{
policies.Set<IMapParameterNameToRegistrationNamePolicy>(new MapParameterNameToRegistrationNamePolicy(), new NamedTypeBuildKey(implementationType, name));
}
}
public interface IMapParameterNameToRegistrationNamePolicy : IBuilderPolicy
{
}
public class MapParameterNameToRegistrationNamePolicy : IMapParameterNameToRegistrationNamePolicy
{
}
The code and test can be found in the source code of the TecX project on CodePlex. Project TecX.Unity (folder Injection).
Why dont you create a command Factory
public class CommandFactory (IUnityContainer container) : ICommandFactory
{
public ICommand CreateSaveCommand()
{
return container.Resolve("SaveCommand");
}
public ICommand CreateLoadCommand()
{
return container.Resolve("LoadCommand");
}
}
public ViewModel(ICommandFactory commandFactory)
{
LoadCommand = commandFactory.CreateLoadCommand();
SaveCommand = commandFactory.CreateSaveCommand();
}

Resources