|
I have a method something like this.
private void PrintSomething()
{
}
then calling this method like this
MethodInvoker mi = new MethodInvoker(PrintSomething);
mi.BeginInvoke(null, null);
This will work pretty well on win7 and up, but if running it on Win XP will cause a very high cpu usage and will it eat up the memory then the desktop will freeze.
but just calling the method synchronously everything is fine under win XP.
private void btn_click(object sender, EventArgs e)
{
PrintSomething();
}
Any thought about this?
I will appreciate for any advice will.
Thanks.
modified 2-Feb-16 1:03am.
|
|
|
|
|
Suggestions:
1. Try debugging it. Or it's not possible?
2. If not debugging, do some logging within the PrintSomething method. By what you're saying, it looks like you might end up calling PrintSomething method too many times
3. You can also ask if IsInvokeRequired first.
4. A profiler? (dotTrace comes to mind)
Best,
John
-- Log Wizard - a Log Viewer that is easy and fun to use!
|
|
|
|
|
Thanks for the advice, but I was end up not using asynchronous method execution if the OS is windows XP, it is hard to deal with some user that cant get over to their OS's and hardware.
|
|
|
|
|
mi.BeginInvoke(null, null) executes your PrintSomething() method asynchronously on a threadpool thread. Is that what you intended or did you mean to use Control.BeginInvoke(mi) to execute PrintSomething on the UI thread?
|
|
|
|
|
Yeah i just want to execute it asynchronously, but i was end up using synchronous if it detects that the OS is XP.
BTW Thanks
|
|
|
|
|
hello,
I want to retrieve a date from the result of a query in a variable:
using (OdbcConnection connexion_source = new OdbcConnection(con_source))
using (OdbcCommand command_source = connexion_source.CreateCommand())
{
command_source.CommandText = "select max(date) from thisdet;";
OdbcDataAdapter MyAdapter = new OdbcDataAdapter(command_source);
MyAdapter.Fill(dt_source);
}
i want to retrieve the date in a variable.
you have idea ?
thank you
|
|
|
|
|
Whenever you want to retrieve just a single value from a database you should use ExecuteScalar[^] :
using (OdbcConnection connexion = new OdbcConnection(con_source))
using (OdbcCommand command = connexion.CreateCommand())
{
command.CommandText = "select max(date) from thisdet;";
object result = command.ExecuteScalar();
if(result != null)
{
DateTime resultDate = (DateTime)result;
}
else
{
}
}
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
|
|
|
|
|
thank's
|
|
|
|
|
You're welcome!
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
|
|
|
|
|
I'm basically following the approach here:
Functional Fun: Weak Events in .Net, the easy way[^]
So I designed a helper to get the IObserveble:
public static IObservable<EventPattern<PropertyChangedEventArgs>> ObservePropertyChanged(this INotifyPropertyChanged collection, string PropertyName)
{
return Observable.FromEventPattern<PropertyChangedEventHandler, PropertyChangedEventArgs>(
handler => (sender, e) => handler(sender, e),
handler => collection.PropertyChanged += handler,
handler => collection.PropertyChanged -= handler)
.Where(evt => evt.EventArgs.PropertyName == PropertyName);
}
Then I copied the SubscribeWeakly method:
public static IDisposable SubscribeWeakly<T, TTarget>(this IObservable<T> observable, TTarget target, Action<TTarget, T> onNext) where TTarget : class
{
var reference = new WeakReference(target);
IDisposable subscription = null;
subscription = observable.Subscribe(item =>
{
var currentTarget = reference.Target as TTarget;
if (currentTarget != null)
{
onNext(currentTarget, item);
}
else
{
subscription.Dispose();
}
});
return subscription;
}
My question is simply, is this really all that is required to create a WeakEvent Listener with Rx? I'm really confused as the ObservePropertyChange method subscribes to the event, seemingly, in the normal strong reference way. I thought Rx changed the event into a sequence of the type you are getting, and that it enables common methods you would like to use in async programming?
Also, the code blocks that I commented out, never returned null, even in the code originally posted on the web page. It was supposed to check if the onNext was connected to any non-static incidence, but as far as I can tell, that will never happen?
I also have sort of a side question, and that is how do I enable to write an Expression in the code that allows me to write:
ObservePropertyChanged(Myclass, s => s.MyPropertyInMyClass)
I understand how to use normal Expressions like:
Expression<Func<int, int, string>> expression = (a, b) => "soemthing";
What I dont get, is how to referance the incomming class, and specify the returning property?
|
|
|
|
|
Kenneth Haugland wrote: My question is simply, is this really all that is required to create a WeakEvent Listener with Rx? To make it actually work, I changed the class WeakSubscriber like this (I don't know why it would be working for the author like he posted it):
private class WeakSubscriber
{
public void Subscribe(ObservableCollection<object> collection)
{
collection.ObserveCollectionChanged().SubscribeWeakly(this, HandleEvent);
}
private static void HandleEvent(WeakSubscriber target, EventPattern<NotifyCollectionChangedEventArgs> item)
{
target.HandleEvent(item);
}
private void HandleEvent(EventPattern<NotifyCollectionChangedEventArgs> item)
{
Console.WriteLine("Event received by Weak subscription");
}
}
Which makes the delegate onNext carry no reference to the WeakSubscriber-object.
Then you can also un-comment if(onNext.Target != null){..} again.
Kenneth Haugland wrote: I'm really confused as the ObservePropertyChange method subscribes to the event, seemingly, in the normal strong reference way. The trick here is that there's that WeakSubscriber-object which only you hold a strong reference to. The only other reference is a WeakReference in the observable-subscription-object. When you drop your strong reference to it (and a GC occurred), the next event will "trigger" the else-branch with subscription.Dispose() which then causes the strong reference from the collection-eventhandlers to also be dropped.
Kenneth Haugland wrote: I also have sort of a side question Will get back to you later if no one else answered until then
Edit: code block updated
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
modified 30-Jan-16 11:14am.
|
|
|
|
|
Thank you, his article makes so much more sense too now.
Sascha Lefèvre wrote: The trick here is that there's that WeakSubscriber-object which only you hold a strong reference to. The only other reference is a WeakReference in the observable-subscription-object. When you drop your strong reference to it (and a GC occurred), the next event will "trigger" the else-branch with subscription.Dispose() which then causes the strong reference from the collection-eventhandlers to also be dropped.
In my head, this makes the event subscribed with the Rx EventPattern different than a normal delegate? When I did the mediator, I had to use a WeakEventManager to make this happen, so it this implemented by default with the Rx pattern?
btw: I was pondering using this:
Generic weak event handlers | Pure silver[^]
But I fealt it would just complicate matters further.
|
|
|
|
|
Short update on just one point: It does work as a weak event the way he posted it (without my modified WeakSubscriber class) if you comment out that if-check like you did. But then you would also be able to do this:
private class WeakSubscriber
{
public void Subscribe(ObservableCollection<object> collection)
{
collection.ObserveCollectionChanged().SubscribeWeakly(this, HandleEvent);
}
private void HandleEvent(WeakSubscriber target, EventPattern<NotifyCollectionChangedEventArgs> item)
{
Console.WriteLine("Event received by Weak subscription");
}
} And here the onNext-delegate carries a reference to the WeakSubscriber-object so that it will not be GC'ed when you release your "own" reference to it. That's what he wanted to prohibit with that if-check. But that if-check doesn't work in conjunction with an anonymous delegate ((target, item) => target.HandleEvent(item) ) (which is why I replaced it with that intermediate static HandleEvent-method) because an anonymous delegate gets converted into an anonymous class by the compiler of which a non-static method is being called. (Since that anonymous class doesn't carry a reference to the WeakSubscriber-object it still works without the if-check.)
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
|
|
|
|
|
Yes, I understood that, and the target is actually the Weakreferance. My question is more of what happens inside the Rx compiler when you subscribe to the event:
public static IObservable<EventPattern<NotifyCollectionChangedEventArgs>> ObserveCollectionChanged(this INotifyCollectionChanged collection)
{
return Observable.FromEventPattern<NotifyCollectionChangedEventHandler, NotifyCollectionChangedEventArgs>(
handler => (sender, e) => handler(sender, e),
handler => collection.CollectionChanged += handler,
handler => collection.CollectionChanged -= handler);
}
I get that these event get converted into a stream by use of Subject class. Since the event is subscribed before the weak reference is implemented, in fact it comes directly from the method above. What you are telling me (hopefully I'll get this right ) is that a non-static void, will generate a strong reference, and the static (shared) void creates a weak reference. So the event subscription in the code above is not important?
|
|
|
|
|
Observable.FromEventPattern<..>(..) doesn't subscribe to the event immediately. This only happens once you subscribe to the Observable, so here in SubscribeWeakly<..>(..). Then it executes that handler => collection.CollectionChanged += handler -delegate to subscribe to the event and calls the onNext-delegate provided by Subscribe(..) whenever that event occurs.
But if you call SubscribeWeakly<..>(..) with an onNext-delegate that calls an instance (non-static) method of WeakSubscriber then that delegate holds a normal (=strong) reference to the instance of the class of that method - because it has to call the method on the class instance. That delegate becomes part of the delegate that is constructed in SubscribeWeakly<..>(..) (item => {..}) and passed to the Observable when calling Subscribe(..) on it. So then the Observable holds a normal (=strong) reference to the WeakSubscriber-instance which then can't get GC'ed any more even if you release your reference to it. The code in ObserveCollectionChanged(..) is of course important but not related to this issue.
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
|
|
|
|
|
Kenneth Haugland wrote: I also have sort of a side question, and that is how do I enable to write an Expression in the code that allows me to write:
ObservePropertyChanged(Myclass, s => s.MyPropertyInMyClass) Caution: Code dump incoming!
using System;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Reactive;
using System.Reactive.Linq;
using System.Reflection;
namespace RxPropertyChanged
{
class A : NotifierBase
{
public string ID { get; set; }
public string Name
{
get { return name; }
set { SetProperty(ref name, value); }
}
private string name;
}
class WeakPropertyChangedSubscriber<TTarget, TProperty>
where TTarget : INotifyPropertyChanged
{
private Action<EventPattern<PropertyChangedEventArgs>> EventAction;
public WeakPropertyChangedSubscriber(TTarget target, Expression<Func<TTarget, TProperty>> propertyExpr, Action<EventPattern<PropertyChangedEventArgs>> eventAction)
{
EventAction = eventAction;
target.FromPropertyChanged(propertyExpr).SubscribeWeakly(this, HandleEvent);
}
private static void HandleEvent(WeakPropertyChangedSubscriber<TTarget, TProperty> subscriber, EventPattern<PropertyChangedEventArgs> item)
{
subscriber.EventAction(item);
}
}
public static class IObservableExtensions
{
public static IObservable<EventPattern<PropertyChangedEventArgs>> FromPropertyChanged<TTarget, TProperty>(this TTarget target, Expression<Func<TTarget, TProperty>> propertyExpr)
where TTarget : INotifyPropertyChanged
{
var propertyInfo = (propertyExpr.Body as MemberExpression)?.Member as PropertyInfo;
if (propertyInfo == null)
throw new ArgumentException("The specified expression does not reference a property.", nameof(propertyExpr));
return Observable.FromEventPattern<PropertyChangedEventHandler, PropertyChangedEventArgs>(
eventHandler => (s, e) => eventHandler(s, e),
propertyChangedEventHandler => target.PropertyChanged += propertyChangedEventHandler,
propertyChangedEventHandler => target.PropertyChanged -= propertyChangedEventHandler)
.Where(evt => evt.EventArgs.PropertyName == propertyInfo.Name);
}
public static IDisposable SubscribeWeakly<TEventPattern, TSubscriber>(this IObservable<TEventPattern> observable, TSubscriber subscriber, Action<TSubscriber, TEventPattern> onNext)
where TSubscriber : class
{
if (onNext.Target != null)
throw new ArgumentException("onNext must refer to a static method, or else the subscription will still hold a strong reference to target");
var reference = new WeakReference(subscriber);
IDisposable subscription = null;
subscription = observable.Subscribe(item =>
{
var currentTarget = reference.Target as TSubscriber;
if (currentTarget != null)
{
onNext(currentTarget, item);
}
else
{
Console.WriteLine("subscription.Dispose()");
subscription.Dispose();
}
});
return subscription;
}
}
class Program
{
static void Main(string[] args)
{
A a1 = new A() { ID = "a1" };
A a2 = new A() { ID = "a2" };
Action<A, EventPattern<PropertyChangedEventArgs>> eventAction = (obj, evt) => Console.WriteLine($"{obj.ID}.{evt.EventArgs.PropertyName} = {obj.Name}");
var subscriberA1 = new WeakPropertyChangedSubscriber<A, string>(a1, x => x.Name, evt => eventAction(a1, evt));
var subscriberA2 = new WeakPropertyChangedSubscriber<A, string>(a2, x => x.Name, evt => eventAction(a2, evt));
a1.Name = "name1.1";
a2.Name = "name2.1";
subscriberA1 = null;
GC.Collect();
Console.WriteLine("Full collection completed");
a1.Name = "name1.2";
a2.Name = "name2.2";
Console.Read();
}
}
}
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
|
|
|
|
|
Thanks, this is really helpful. Also, I finally gave in and bought a book on Linq.
|
|
|
|
|
Which book did you buy? I bought one or two but they weren't really good. Ended up learning from online resources.
Was my last reply in the other branch of the thread an answer to your question?
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
|
|
|
|
|
Yes, your code solves my question, but I think I need to learn more about the usage of TTarget and TProperty stuff and their links to Expression. What are the conditions of using them, what are the limitations, and how can I set up links to them etc. I feel that these questions would take 100 pages or more to explain, so I had to read up on something. If I can read a book to get the basics down first I end up having a million silly questions to ask to get it right.
I already have Linq to objects book[^], and that was really good at showing basic usage and an overall overview of how to use and create custom queries. So I got Linq in Action[^] and hope that is will provide some more answers. After the original buzz of Linq in 2008 -2009 there seem to be very few new books, except one from Microsoft.
Edit:
After looking at your examples and reading a bit I finally understood what I was supposed to do now, so I can show you in code what I meant:
public static IObservable<EventPattern<PropertyChangedEventArgs>> ObservePropertyChanged<TSource,TProperty>(this TSource collection, Expression<Func<TSource, TProperty>> propertyExpr) where TSource : INotifyPropertyChanged
{
Contract.Requires(collection != null);
Contract.Requires(propertyExpr != null);
var body = propertyExpr.Body as MemberExpression;
if (body == null)
throw new ArgumentException("The specified expression does not reference a property.", "property");
var propertyInfo = body.Member as PropertyInfo;
if (propertyInfo == null)
throw new ArgumentException("The specified expression does not reference a property.", "property");
string propertyName = propertyInfo.Name;
return Observable.FromEventPattern<PropertyChangedEventHandler, PropertyChangedEventArgs>(
handler => (sender, e) => handler(sender, e),
handler => collection.PropertyChanged += handler,
handler => collection.PropertyChanged -= handler)
.Where(evt => evt.EventArgs.PropertyName == propertyName);
}
This should greatly reduce typing errors (and enable intellisence) compared to requesting a string of the property name only. I assume that TProperty is basically just the result that returns an unidentified object?
modified 31-Jan-16 11:56am.
|
|
|
|
|
Kenneth Haugland wrote: This should greatly reduce typing errors (and enable intellisence) compared to requesting a string of the property name only. Yes, that's the purpose of the Expression.
Kenneth Haugland wrote: I assume that TProperty is basically just the result that returns an unidentified object? TProperty is just the expected type of the property (string in the case of the code I posted before). The expression doesn't do anything by itself, it just enables us to specify the property in a safer way because the compiler checks for us that its return type is of TProperty. The expression then ends up being "dissected" by us again in ObservePropertyChanged(..) in order to get the property name.
It's not completely compile-time safe because you could specify something else than a property which is also returning the correct type of TProperty. That's why those checks are there in ObservePropertyChanged(..) to ensure (at runtime) that the expression is "pointing" at a property. But even that isn't completely safe because you'd still able to call it like this x => someNonTTargetTypedObject.SomeTPropertyTypedProperty.
That could be also be checked though. Maybe an exercise for you
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
|
|
|
|
|
Sascha Lefèvre wrote: to ensure (at runtime) that the expression is "pointing" at a property
Even thats not enough, the property coud be WriteOnly
|
|
|
|
|
Your code works very well, but I don't really like changing the pattern from the original implementation, so I came up with this:
internal class WeakPropertyChangedSubscriber
{
public WeakPropertyChangedSubscriber(object WeakClass, IObservable<EventPattern<PropertyChangedEventArgs>> observable,ref IDisposable Result, Action<EventPattern<PropertyChangedEventArgs>> eventAction)
{
Result = observable.InternalSubscribeToWeakPropertyChange(eventAction, WeakClass, WeakPropertyChangedSubscriber.HandleEvent);
}
public static void HandleEvent(Action<EventPattern<PropertyChangedEventArgs>> subscriber, object reffing, EventPattern<PropertyChangedEventArgs> item)
{
subscriber(item);
}
}
public static IDisposable SubscribeWeakly<T>(this IObservable<T> observable, object WeakClass, Action<EventPattern<PropertyChangedEventArgs>> onNext)
{
IDisposable Result = null;
IObservable<EventPattern<PropertyChangedEventArgs>> ObservableCast = (IObservable<EventPattern<PropertyChangedEventArgs>>)observable;
WeakPropertyChangedSubscriber WeakReferanceChanged = new WeakPropertyChangedSubscriber(WeakClass, ObservableCast, ref Result, onNext);
return Result;
}
private static IDisposable InternalSubscribeToWeakPropertyChange<TEventPattern, TSubscriber, TWeakReferance>(this IObservable<TEventPattern> observable, TSubscriber subscriber, TWeakReferance refing, Action<TSubscriber, TWeakReferance, TEventPattern> onNext)
where TSubscriber : class where TWeakReferance : class
{
if (onNext.Target != null)
throw new ArgumentException("onNext must refer to a static method, or else the subscription will still hold a strong reference to target");
var reference = new WeakReference(refing);
IDisposable subscription = null;
subscription = observable.Subscribe(item =>
{
var currentTarget = reference.Target as TWeakReferance;
if (currentTarget != null)
{
onNext(subscriber,currentTarget, item);
}
else
{
Console.WriteLine("subscription.Dispose()");
subscription.Dispose();
}
});
return subscription;
}
This way you can use it almost like the normal subscribe. Only difference is that you have to say what object that should have a weak reference:
var er = ObservableEx.Observe(C, o => o.Name).SubscribeWeakly(C,arg => PropertyChanged(arg.Sender, arg.EventArgs));
C.Name = "test";
C = null;
GC.Collect();
C = new ViewModelB();
C.Name = "2";
There has to be a way to get the class trough reflection? I coudnt find it now though.
|
|
|
|
|
I have a form with some listviews and some label's (to punctualize the LVs and LBs are in a Panel on the form), in a nutshell, these LVs show up some items from a source, all works OK, when i show the form (all it's controls are disabled initially) the LVs loads some items and show up exactly as i expected.
I decided to rearrange theese LVs and LBs with a tablelayoutpanel (TBP), so i placed a TBP inside the form and i moved LVs and LBs in the TBP in this manner:
Label1 | Label2 | Label3 (AutoSize)
-------+--------+--------
LV1 +LV2 +LV3 (50%)
-------+--------+--------
Label4 | Label5 | Label6 (AutoSize)
-------+--------+--------
LV4 +LV5 +LV6 (50 %)
and i haven't modified the code.
When i launch the program ... the LVs don't show anything ....
to countercheck i move one LV ouside the TBP and items return to show ups ...
Where i'm in Wrong ?
Thanks in Advance & sorry for my Ugly English
modified 30-Jan-16 7:54am.
|
|
|
|
|
I found the problem.
In the load events of the form there is an initialization that use a recursive alghoritm. Using TableLayoutPane this recursion in blocked because the cicle on This.Controls do not return the controls that i moved in TableLayoutPanel so that controls can't be initialized.
|
|
|
|
|
Glad you found the answer: there's an internet delay here, where I am, and I didn't see your post until after I posted my questions.
There is a well-known problem with Items not showing up in the WinForm ListView when it's in 'Detail View, and is loaded at run-time. You can find several threads on that on StackOverFlow.
«In art as in science there is no delight without the detail ... Let me repeat that unless these are thoroughly understood and remembered, all “general ideas” (so easily acquired, so profitably resold) must necessarily remain but worn passports allowing their bearers short cuts from one area of ignorance to another.» Vladimir Nabokov, commentary on translation of “Eugene Onegin.”
|
|
|
|
|